Entity Framework 4.0を使用していて(.NET 3.5で使用できるように)、既存のデータベースからDALを生成しました。
データベースには、次の列を持つ2つのテーブルがあります(NULLにすることはできません)。
- tblWeapon(WeaponId PK、WeaponLabel)
- tblShot(ShotId PK、WeaponId)
そして、tblShotのWeaponIdにはtblWeaponへの外部キーがあります。
次に、生成されたエンティティは次のようになります。
public class Weapon {
public int WeaponId { ... }
public string WeaponLabel { ...}
public EntityCollection Shots { ... }
}
public class Shot {
public int ShotId { ... }
public EntityReference WeaponReference { ... }
public Weapon Weapon { ... }
}
私のコードには、個々のテーブルをフィルタリングするための基準を含むShotFilterクラスとWeaponFilterクラスがあります。エンティティのフィルターは動的に生成されるため、クエリの生成をそれぞれのフィルタークラスに分散させたいと思います。各フィルターはを返し、IQueryable<T>
必要に応じてそれらを結合して、目的の結果を達成します。
私がやりたいのは、ラベルにテキストが含まれている武器を参照するすべてのShotオブジェクトを取得することです0.5
。
問題は、フィールドが含まれていないため(IQueryable<Shot>
)にIQueryable<Weapon>
内部Shot
結合を実行しようとしたときに発生します。Webを精査し、ほとんど何も見つからなかった後、答えがオブジェクト自体に参加することであるフォーラム投稿を見つけました。だから私はこれを試し、私が期待していた結果を得ました:WeaponId
WeaponReference
var oWeaponQuery = from w in oDc.Weapons select w;
oWeaponQuery = oWeaponQuery.Where(w => w.Label.Contains("0.5"));
var oShotQuery = from s in oDc.Shots select s;
oShotQuery = oShotQuery.Join(oWeaponQuery, s => s.Weapon, w => w, (s, w) => s);
しかし、SQL Server Profilerを使用してクエリされた実際のSQLを調べたところ、次のひどいステートメントが表示されました(そして少し嘔吐しました)。
SELECT
1 AS [C1],
[Extent1].[ShotId] AS [ShotId],
[Extent1].[WeaponId] AS [WeaponId]
FROM [dbo].[tblShot] AS [Extent1]
INNER JOIN [dbo].[tblWeapon] AS [Extent2] ON EXISTS (SELECT
cast(1 as bit) AS [C1]
FROM ( SELECT cast(1 as bit) AS X ) AS [SingleRowTable1]
LEFT OUTER JOIN (SELECT
[Extent3].[WeaponId] AS [WeaponId]
FROM [dbo].[tblWeapon] AS [Extent3]
WHERE [Extent1].[WeaponId] = [Extent3].[WeaponId] ) AS [Project1] ON 1 = 1
LEFT OUTER JOIN (SELECT
[Extent4].[WeaponId] AS [WeaponId]
FROM [dbo].[tblWeapon] AS [Extent4]
WHERE [Extent1].[WeaponId] = [Extent4].[WeaponId] ) AS [Project2] ON 1 = 1
WHERE ([Project1].[WeaponId] = [Extent2].[WeaponId]) OR (([Project2].[WeaponId] IS NULL) AND ([Extent2].[WeaponId] IS NULL))
)
WHERE (CAST(CHARINDEX(N'0.5', [Extent2].[Label]) AS int)) > 0
では、これを正しい方法で、または少なくとも効率的な方法で行うにはどうすればよいでしょうか。または、動的で分散された方法でクエリ生成を整理する方法に関する他の提案はありますか?
ありがとう!
詳細で更新
結合を行う際の私の問題の一部は、プロパティShot
がないために生成されたエンティティにEFを使用することです。それを管理するプロパティWeaponId
だけがあります。WeaponReference
したがって、私の参加では、次を使用できると期待しています。
oShotQuery = oShotQuery.Join(oWeaponQuery, s => s.WeaponId, w => w.WeaponId, (s, w) => s);
ただしWeaponId
、のプロパティではないため、これは機能しませんShot
。
それから私はこれを試しました(これもまた奇妙に思えます):
oShotQuery = oShotQuery.Join(oWeaponQuery, s => s.Weapon.WeaponId, w => w.WeaponId, (s, w) => s);
そしてそれは機能し、かなり簡潔なSQLを生成します(例外を除いて):
SELECT
1 AS [C1],
[Extent1].[ShotId] AS [ShotId],
[Extent1].[WeaponId] AS [WeaponId]
FROM [dbo].[tblShot] AS [Extent1]
INNER JOIN [dbo].[tblWeapon] AS [Extent2] ON ([Extent1].[WeaponId] = [Extent2].[WeaponId]) OR
(([Extent1].[WeaponId] IS NULL) AND ([Extent2].[WeaponId] IS NULL))
WHERE (CAST(CHARINDEX(N'0.5', [Extent2].[Label]) AS int)) > 0
そして、その例外はこれです:OR (([Extent1].[WeaponId] IS NULL) AND ([Extent2].[WeaponId] IS NULL))
。私はそれらが両方あるところは欲しくないNULL
、私はそれらが等しいところだけが欲しい。