1

Entity Framework 4.0を使用していて(.NET 3.5で使用できるように)、既存のデータベースからDALを生成しました。

データベースには、次の列を持つ2つのテーブルがあります(NULLにすることはできません)。

  1. tblWeapon(WeaponId PK、WeaponLabel)
  2. 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を精査し、ほとんど何も見つからなかった後、答えがオブジェクト自体に参加することであるフォーラム投稿を見つけました。だから私はこれを試し、私が期待していた結果を得ました:WeaponIdWeaponReference

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、私はそれらが等しいところだけが欲しい。

4

1 に答える 1

0

私がやりたいことは、ラベルにテキスト 0.5 が含まれている武器を参照するすべての Shot オブジェクトを取得することです。

これは私が使用するクエリです:

var oShotQuery = oDc.Shots.Where(s => s.Weapon.Label.Contains("0.5"))

生成された SQL に関する限り、使用することを考えていなかったものが大量に投入されたとしても、後回しにしないでください。これらのクエリは、少なくとも手動で生成できるクエリと同じくらいのパフォーマンスを発揮する傾向があります。重要なのは、元のクエリを単純にすることです。

アップデート

さまざまなクエリを動的に生成し、後でそれらを結合できるようにしたいと考えています。

これはどう?

var oShotQuery = oShotQuery.Where(
    o => oWeaponQuery.Any(w => w.WeaponId == o.Weapon.WeaponId))
于 2012-01-31T20:10:21.830 に答える