優れている、あなたは本当に、単一のクエリを実行することはできません少なくとも2つの異なるデータベースにまたがっていて、少なくともいくつかのヘルプ構成を設定する必要はありません(いずれのデータベースにも存在し、実際にパフォーマンスを向上させるかどうかは分かりません)。
しかし、それはあなたのクエリを改善することができないということを意味するものではありません。クエリを実行するデータベースエンジンに頼ることができない場合、私たちはそれを自分で行うことができます。この場合、基本的にはLMNotes
エンティティのクエリだけです。次に、Employees
セットの従業員に参加します。
だから、素朴な解決策は、次のようになります。もちろん
var notes = lmCtx.LMNotes
.Where(lmnote => lmnote.lnt_recordId == 5566 && lmnote.lnt_tableId == 1)
.Select(lmnote =>
{
return new NoteInfo
{
Note = lmnote,
CreatedBy = tessCtx.Employees.FirstOrDefault(e => e.EmployeeId == lmnote.lnt_createdById),
ModifiedBy = tessCtx.Employees.FirstOrDefault(e => e.EmployeeId == lmnote.lnt_modifiedById)
};
})
.ToList();
を、これはLMNotes
上の単一のクエリを実行しながら、これはまだ結果における各ノートのための2つの別々のクエリを実行します。それで、EFがそこでやったことよりも実際には良いことではありません。
しかし、私たちができることは、ルックアップを追加することです。私は、従業員のセットは多少限定されていると思うので、一度各従業員を取得するだけで意味があります。
private Dictionary<int, Employee> employees = new Dictionary<int, Employee>();
private Employee GetEmployee(int employeeId)
{
Employee employee;
if (!employees.TryGetValue(employeeId, out employee))
{
employee = tessCtx.Employees.FirstOrDefault(e => e.EmployeeId == employeeId);
employees[employeeId] = employee;
}
return employee;
}
public List<NoteInfo> GetNotes()
{
return lmCtx.LMNotes
.Where(lmnote => lmnote.lnt_recordId == 5566 && lmnote.lnt_tableId == 1)
.Select(lmnote =>
{
return new NoteInfo
{
Note = lmnote,
CreatedBy = GetEmployee(lmnote.lnt_createdById),
ModifiedBy = GetEmployee(lmnote.lnt_modifiedById)
};
})
.ToList();
}
これは、各従業員を一度検索して従業員オブジェクトをキャッシュするだけです。
また、ここで2回目の通過を行い、最初にメモを読み込んだ後にすべての従業員を一度に取得することもできます。このようなもの:
public List<NoteInfo> GetNotes()
{
var employeeIds = new HashSet<int>();
var notes = lmCtx.LMNotes
.Where(lmnote => lmnote.lnt_recordId == 5566 && lmnote.lnt_tableId == 1)
.Select(lmnote =>
{
// remember the ids for later
employeeIds.Add(lmnote.lnt_createdById);
employeeIds.Add(lmnote.lnt_modifiedById);
return new NoteInfo
{
Note = lmnote,
CreatedBy = null,
ModifiedBy = null
};
})
.ToList();
var employees = tessCtx.Employees
.Where(e => employeeIds.Contains(e.EmployeeId))
.ToList()
.ToDictionary(e => e.EmployeeId);
foreach (var noteInfo in notes)
{
noteInfo.CreatedBy = employees[noteInfo.Note.lnt_createdById];
noteInfo.ModifiedBy = employees[noteInfo.Note.lnt_modifiedById];
}
return notes;
}
これは、各データベースに対して1つのクエリしか実行しません。
一見すると、すべてのものを '.AsEnumerable() 'で実体化し、それを照会します。これはメモリの問題の原因かもしれません。それを削除し、それを標準の 'IQueryable'インタフェースとして使用することで、メモリ使用量が目立って減少するはずです。 – Scott
はい、次のエラーが表示されます: '指定されたLINQ式には、異なるコンテキストに関連付けられたクエリへの参照が含まれています。これが私が 'AsEnumerable()'を使用した理由です –
'AsEnumerable()'を使うことで、あなたは本質的にあなたの全体の "クエリ"をメモリ上で実行しています。したがって、データベースからすべてのデータをフェッチしてから、アプリケーション内で結合します。データベースでクエリを効率的に実行するには、 'IQueryable'を使用する必要があります。したがって、両方のエンティティにアクセスできる単一のデータベースコンテキストが必要です。その周りには道はない。 – poke