web-dev-qa-db-ja.com

エラー:「指定されたLINQ式には、異なるコンテキストに関連付けられたクエリへの参照が含まれています」

2つの異なるedmxファイルからの2つのテーブルを含むLINQクエリから、タイトルに示されているエラーが表示されます。クエリは次のとおりです。

var query = (from a in db1.Table1
           join b in db1.Table2 on a.Id equals b.Id
           orderby a.Status
           where b.Id == 1 && a.Status == "new"
           select new
           {
               Id = a.Id,
               CompanyId = (from c in db2.Company
                            where s.Id == a.Id
                            select
                            new { c.CompanyId })
           });

db1およびdb2は、2つの異なるedmxファイルに関連付けられているコンテキストです。このエラーを解決するにはどうすればよいですか?

58
Ashiq A N

2つのデータベースクエリを実行する必要があります。

_var IDs =  (from a in db1.Table1 
            join b in db1.Table2 on a.Id equals b.Id 
            orderby a.Status 
            where b.Id == 1 && a.Status == "new" 
            select new a.Id).ToArray();

var query = from c in db2.Company
            join a in IDs on c.Id equals a.Id
            select new { Id = a.Id, CompanyId = c.CompanyId };
_

.ToArray()は重要です。 EFが結合クエリを実行しようとするのを防ぎます(2つの異なるコンテキストを使用するため失敗します)。遅延読み込みを続けたい場合は、.AsEnumerable()を使用できます。


あなたのフォローアップの質問:

LINQクエリをさらに最適化する他の方法はありますか?つまり、単一のLINQクエリ自体でアクションを実行しますか?

元のクエリを正常に実行するには、単一のデータコンテキストのみを使用する必要があります。つまり、すべてのデータが単一のEDMXから利用可能である必要があり、これは単一の接続文字列を意味します。それを実現する方法はいくつかあります。

  • 両方のテーブルが同じデータベースにある場合は、両方を単一のEDMXに追加します。
  • それらが異なるデータベース上にあるが同じインスタンスにある場合、他のデータベースのテーブルから選択するデータベースの1つにビューを作成し、ローカルのテーブルとビューを単一のEDMXに追加します。
  • それらが異なるインスタンス/サーバー上にある場合、リンクサーバーを作成し、リンクサーバーにテーブルのビューを作成し、ローカルテーブルとビューを単一のEDMXに追加します。
109
Allon Guralnek

最初のコンテキストのモデルに2番目のテーブルを追加する必要があります。これが複数のデータベースにある場合、Linq to Objects結合を使用して、クライアント側でセカンダリルックアップを実行する必要があります。

2
Jim Wooley

使用するすべての.EDMXのリソースで満たされたEntityConnectionを手動で作成する必要があります。 app.configに接続を追加するか、プログラムで接続して追加できます。次に、準備されたEntityConnectionを使用してDBContextを作成できます。

方法a)

<add name="MyConnection"
connectionString="metadata=res://*/Entities.ModuleA.csdl|res://*/Entities.ModuleA.ssdl|res://*/Entities.ModuleA.msl|res://*/Entities.ModuleB.csdl|res://*/Entities.ModuleB.ssdl|res://*/Entities.ModuleB.msl;
provider=System.Data.SqlClient;provider connection string=&quot;MyConnectionString&quot;"
providerName="System.Data.EntityClient" />

using (EntityConnection oEntityConnection =
    new EntityConnection("name=MyConnection"))
{
    using(DbContext oDBContext = new DbContext(oEntityConnection))
    {
        //your code - available are entities declared in Entities.ModuleA and Entities.ModuleB
    }
}

方法b)

 using (EntityConnection oEntityConnection =
        new EntityConnection(new MetadataWorkspace(
        new string [] { 
"res://Entities.ModuleA/", 
"res://Entities.ModuleB/" 
},
        new Assembly[] { 
Assembly.GetAssembly(typeof(Entities.ModuleA.AnyType)),
Assembly.GetAssembly(typeof(Entities.ModuleB.AnyType)) 
}
        )))
    {
        using(DbContext oDBContext = new DbContext(oEntityConnection))
        {
            //your code - available are entities declared in Entities.ModuleA and Entities.ModuleB
        }
    }
0