0

オブジェクトのセットにEFを使用していて、他の2つのテーブルの一致するエントリを使用して1つのタイプのオブジェクトをクエリしたいと思います。これは、クエリをXML出力にダンプするためのものです。元のデータでは、各従業員が常にComputerオブジェクトのインスタンスを1つ以上持っていたため(以下のソリューション#2)、最初は結合を使用しましたが、必ずしもそうとは限りません。

ここでの目的のために、想像してみてください。

  • Employeeオブジェクト、
  • 各従業員にはEmployeeType(いくつかの固定エントリ)と
  • 各従業員には、0個以上のコンピューターオブジェクト(通常は0〜3)があります。
  • 各コンピューターは1人の従業員に属しており、すべての従業員がコンピューターを持っているわけではありません。
  • 各従業員には、検索の基礎となる基準(部門など)があります。

だから私はいくつかの可能な解決策を見ました:

  1. ループ内でEmployee.Computer.Load()を使用しますが、行数が10,000を超えると、パフォーマンスが大幅に低下します。

  2. クエリで結合を使用しますが、コンピューターを持たないすべての従業員が除外されます。

  3. Linq to Entitiesを使用しますが、これには#1のオーバーヘッドがあるようです。コンピューターをロードすると、各従業員のデータベースにヒットします

  4. 2番目のクエリ(Computer.Employee.Divisionと一致するすべてのコンピューター)を使用してから、Employeeループで、指定された従業員の任意のコンピューターを追加します。これを実装しているときに、( ToList()を使用して)2番目のクエリを実行するだけで、EFが正しいEmployee.Computerリストに必要なオブジェクトを入力することがわかりました。

ここで、#4は10k以上ではなく2つのデータベースヒットのみでデータをロードし、EntityFrameworkは実際にオブジェクトを照合して、すべての関係を作成します。

私の質問

  • #4では、EFがEmployee.Computerリストにデータを入力するという事実は、私が信頼できるものですか?もしそうなら、私にドキュメントを教えてもらえますか?
  • #4より良い方法はありますか?

更新:まあ、バガー。申し訳ありませんが、私は単にそれを吹きました。私は「Computer」テーブルとの関係に焦点を合わせていましたが、最初にnullをテストせずに明示的なEmployee.EmployeeTypeReference.Load()を使用していたという事実を見逃したため、「Computer」リストはまったく問題になりませんでした。

これは、いくつかのパフォーマンステストを実行し、Craigのソリューションをミックスに追加したときにのみ見つかりました。実際、レコードは「従業員」や「コンピューター」ではなく抽象化であり、私は(条件付きで)XML出力のすべてのフィールドを含みますが、名前、ID(PK)、ID(FK)に加えて小さいです。 「従業員」テーブルのINT。したがって、EFは投影よりもそれほど重くないオブジェクトを作成するため、パフォーマンスは同様であると私は推測しました。

とにかく、これが「経過」時間がこのクエリの前と結果のXMLが作成された後の違いであった場合の結果です。

  • ケース1:#2と同じですが、Include()ステートメントを使用します。

    list = ve.Employee.Include("Computer").Include("EmployeeType").Where(e => e.Division.ID == divId).OrderBy(e => e.Name);

    経過:4.96、5.05

  • ケース2:インラインLoad()を使用します:

    list = ve.Employee.Where(e => e.Division.ID == divId).OrderBy(e => e.Name);

    経過:74.62

  • ケース3:#4と同じですが、Include()ステートメントを使用します。

    list = from e in ve.Employee.Include("Computer").Include("EmployeeType") where e.Division.ID == divId orderby e.Name select e;

    経過:4.91、5.47

  • ケース4:インラインLoad()を使用します:

    list = from e in ve.Employee where e.Division.ID == divId orderby e.Name select e;

    経過:74.20

  • ケース5:* Include( "EmployeeType")を使用し、 "Computer"クエリを分離して、EFに関連付けさせます。

    elist = ve.Employee.Include("EmployeeType").Where(te => te.Division.ID == divId).OrderBy(e => e.Name).ToList(); alist = ve.Alias.Where(a => a.Employee.Division.ID == divId).ToList();

    経過:4.50、4.02

  • ケース6:クレイグの予測の提案:

    elist = from te in ve.ThesaurusEntry where te.Division.ID==divID orderby te.Name select new { ID = te.ID, Name = te.Name, Type = te.EmployeeType.Name, Freq = te.Frequency, Aliases = from a in te.Alias select new { ID = a.ID, Name = a.Name } };

    経過:0.73、1.25

結論

Load()は高価なので、Include()を使用するか、少なくともIsLoadedでテストしてください

投影は少し面倒ですが、EF修正よりも大幅に高速です。[「狭い」テーブルでのこの限定的なテストで]

4

2 に答える 2

2

リレーションを事前にロードできることを示すことができると思います

Dim employees = From emp in db.Employees.Include("Computer") _
                Select emp
于 2009-08-27T00:06:00.607 に答える
1

ロブのソリューションは機能しますが (+1)、従業員やコンピューターなどのすべてのフィールドが必要ない場合は、代わりに投影することを強くお勧めします。

var q = from e in Context.Employees
        where e.Division.Id = divisionId
        select new
        {
            Name = e.Name,
            EmployeeType = e.EmployeeType.Description,
            ComputerIds = from c in e.Computers
                          select new 
                          {
                              Id = c.Id
                          }
        };

ここでは、必要なすべてを 1 つのクエリで取得しますが、それ以上のものはありません。必要のないすべてのフィールドは返されません。

XElement手動で XML に変換するのではなく、おそらく s を選択して結果のツリーを保存することもできます。私はこれを試していませんが、うまくいくようです。

#4 に関しては、はい、これに頼ることができますが、IsLoaded呼び出す前に常に確認することをお勧めしますLoad()

于 2009-08-27T13:17:09.783 に答える