2012-05-10 12 views
6

私はEntityFrameworkを4回生成し、LazyローディングのPOCOを無効にしてを使用します。
表1、表2、表3および表4という名前のSQL表があり、それらにいくつかのデータが含まれていると仮定します。
のは、これらのテーブルの簡略化されPOCO表現は、このようになりますと仮定しましょう:以下のコードが実行されるかどうデータベースにデータがあるときに何も返さないクエリ

public class Table1 
{ 
    public int ID; 
    public DateTime TableDate; 
    public int Table2ID; 
    public Table2 Table2; 
    public ICollection<Table3> Table3s; 
} 

public class Table2 
{ 
    public int ID; 
    public string SomeString; 
    public int Table4ID; 
    public Table4 Table4; 
} 

public class Table3 
{ 
    public int ID; 
    public int Table1ID; 
    public Table1 Table1; 
    public decimal SomeDecimal; 
} 

public decimal Table4 
{ 
    public int ID; 
    public string SomeName; 
} 

exec sp_executesql N'SELECT 
[Extent1].[ID] AS [ID], 
[Extent1].[TableDate] AS [TableDate], 
[Extent1].[Table2ID] As [Table2ID] 
FROM [dbo].[Table1] AS [Extent1] 
WHERE ([Extent1].[TableDate] >= @p__linq__0)',N'@p__linq__0 datetime2(7)',@p__linq__0='0001-01-01 00:00:00' 

Database DB = new Database(); // object context 
var result = DB.Table1 
    .Where(x => x.TableDate >= DateTime.MinValue); 

EFは、次のSQL文を生成します

となり、クエリは予想されるデータを返します。

Database DB = new Database(); // object context 
var result = DB.Table1 
    .Include("Table2") 
    .Include("Table2.Table4") 
    .Include("Table3") 
    .Where(x => x.TableDate >= DateTime.MinValue); 

EFは、次のSQL文を生成します:
ただし、以下のコードが実行されるかどう

exec sp_executesql N'SELECT 
[Project1].[ID2] AS [ID], 
[Project1].[ID] AS [ID1], 
[Project1].[TableDate] AS [TableDate], 
[Project1].[ID1] AS [ID2], 
[Project1].[SomeString] AS [SomeString], 
[Project1].[Table4ID] AS [Table4ID], 
[Project1].[ID3] AS [ID3], 
[Project1].[SomeName] AS [SomeName], 
[Project1].[ID4] AS [ID4], 
[Project1].[SomeDecimal] AS [SomeDecimal], 
[Project1].[Table1ID] AS [Table1ID] 
FROM (SELECT 
[Extent1].[ID] AS [ID], 
[Extent1].[TableDate] AS [TableDate], 
[Extent2].[ID] AS [ID1], 
[Extent2].[SomeString] AS [SomeString], 
[Extent2].[Table4ID] AS [Table4ID], 
[Extent3].[ID] AS [ID2], 
[Extent4].[ID] AS [ID3], 
[Extent4].[SomeName] AS [SomeName], 
[Extent5].[ID] AS [ID4], 
[Extent5].[SomeDecimal] AS [SomeDecimal], 
[Extent5].[Table1ID] AS [Table1ID], 
CASE WHEN ([Extent5].[ID] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C1] 
FROM  [dbo].[Table1] AS [Extent1] 
INNER JOIN [dbo].[Table2] AS [Extent2] ON [Extent1].[Table2ID] = [Extent2].[ID] 
LEFT OUTER JOIN [dbo].[Table2] AS [Extent3] ON [Extent1].[Table2ID] = [Extent3].[ID] 
LEFT OUTER JOIN [dbo].[Table4] AS [Extent4] ON [Extent3].[Table4ID] = [Extent4].[ID] 
LEFT OUTER JOIN [dbo].[Table3] AS [Extent5] ON [Extent1].[ID] = [Extent5].[Table1ID] 
WHERE ([Extent1].[TableDate] >= @p__linq__0) 
) AS [Project1] 
ORDER BY [Project1].[ID2] ASC, [Project1].[ID] ASC, [Project1].[ID1] ASC, [Project1].[ID3] ASC, [Project1].[C1] ASC',N'@p__linq__0 datetime2(7)',@p__linq__0='0001-01-01 00:00:00' 

とクエリが何も返さないでしょう。

なぜこのようなことが起こる可能性がありますか?

CREATE TABLE [dbo].[Table1](
[ID] [int] IDENTITY(1,1) NOT NULL, 
[Table2ID] [int] NOT NULL, 
[TableDate] [date] NOT NULL, 
CONSTRAINT [PK_Table1] PRIMARY KEY CLUSTERED 
(
[ID] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 

ALTER TABLE [dbo].[Table1] WITH NOCHECK ADD CONSTRAINT [FK_Table1_Table2] FOREIGN KEY([Table2ID]) 
REFERENCES [dbo].[Table2] ([ID]) 

ALTER TABLE [dbo].[Table1] CHECK CONSTRAINT [FK_Table1_Table2] 

CREATE TABLE [dbo].[Table2](
[ID] [int] NOT NULL, 
[SomeString] [nvarchar](50) NOT NULL, 
[Table4ID] [int] NULL, 
CONSTRAINT [PK_Table2] PRIMARY KEY CLUSTERED 
(
[ID] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 

ALTER TABLE [dbo].[Table2] WITH NOCHECK ADD CONSTRAINT [FK_Table2_Table4] FOREIGN KEY([Table4ID]) 
REFERENCES [dbo].[Table4] ([ID]) 
ON UPDATE CASCADE 

ALTER TABLE [dbo].[Table2] CHECK CONSTRAINT [FK_Table2_Table4] 

CREATE TABLE [dbo].[Table3](
[ID] [int] IDENTITY(1,1) NOT NULL, 
[SomeDecimal] [decimal](18, 4) NOT NULL, 
[Table1ID] [int] NOT NULL, 
CONSTRAINT [PK_Table3] PRIMARY KEY CLUSTERED 
(
[ID] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 

ALTER TABLE [dbo].[Table3] WITH NOCHECK ADD CONSTRAINT [FK_Table3_Table1] FOREIGN KEY([Table1ID]) 
REFERENCES [dbo].[Table1] ([ID]) 
ON DELETE CASCADE 

ALTER TABLE [dbo].[Table3] CHECK CONSTRAINT [FK_Table3_Table1] 

CREATE TABLE [dbo].[Table4](
[ID] [int] NOT NULL, 
[SomeName] [nvarchar](50) NOT NULL, 
CONSTRAINT [PK_Table4] PRIMARY KEY CLUSTERED 
(
[ID] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 

EDIT 2

このクエリは、また何のレコードを返しませんし、最小限の一例として機能することができます後

EDIT

は、上記の表を作成するためのSQL文です:

Database DB = new Database(); 
var result = DB.Table1 
    .Include("Table2") 
    .Where(x => x.TableDate >= DateTime.MinValue); 

生成されたSQL:

exec sp_executesql N'SELECT 
[Extent1].[ID] AS [ID], 
[Extent1].[Table2ID] AS [Table2ID], 
[Extent1].[TableDate] AS [TableDate], 
[Extent2].[ID] AS [ID1], 
[Extent2].[SomeString] AS [SomeString], 
[Extent2].[Table4ID] AS [Table4ID], 
FROM [dbo].[Table1] AS [Extent1] 
INNER JOIN [dbo].[Table2] AS [Extent2] ON [Extent1].[Table2ID] = [Extent2].[ID] 
WHERE ([Extent1].[TableDate] >= @p__linq__0)',N'@p__linq__0 datetime2(7)',@p__linq__0='0001-01-01 00:00:00' 

はさらに、ここで.edmxからの抜粋です:

<EntityContainer> 
     <AssociationSet Name="FK_Table1_Table2" Association="MyModel.Store.FK_Table1_Table2"> 
     <End Role="Table2" EntitySet="Table2" /> 
     <End Role="Table1" EntitySet="Table1" /> 
     </AssociationSet> 
</EntityContainer> 

<!-- ... --> 

<EntityType Name="Table2"> 
    <Key> 
    <PropertyRef Name="ID" /> 
    </Key> 
    <Property Name="ID" Type="int" Nullable="false" /> 
    <Property Name="SomeString" Type="nvarchar" Nullable="false" MaxLength="50" /> 
    <Property Name="Table4ID" Type="int" /> 
</EntityType> 

<!-- ... --> 

<EntityType Name="Table1"> 
    <Key> 
    <PropertyRef Name="ID" /> 
    </Key> 
    <Property Name="ID" Type="int" Nullable="false" StoreGeneratedPattern="Identity" /> 
    <Property Name="TableDate" Type="date" Nullable="false" /> 
    <Property Name="Table2ID" Type="int" Nullable="false" /> 
</EntityType> 

<!-- ... --> 

<Association Name="FK_Table1_Table2"> 
    <End Role="Table2" Type="MyModel.Store.Table2" Multiplicity="1" /> 
    <End Role="Table1" Type="MyModel.Store.Table1" Multiplicity="*" /> 
    <ReferentialConstraint> 
    <Principal Role="Table2"> 
     <PropertyRef Name="ID" /> 
    </Principal> 
    <Dependent Role="Table1"> 
     <PropertyRef Name="Table2ID" /> 
    </Dependent> 
    </ReferentialConstraint> 
</Association> 
+3

何かがEFに納得しているのは、 'Table1'から' Table2'への 'LEFT'結合ではなく' INNER'が必要なことです。 SQLスキーマについてもっと詳しく教えてもらえますか、あるいは間違っている最小限の例がありますか? – AakashM

+0

使用しているマッピングを表示してください。 –

+0

上記の表を作成するためにSQL文で質問を編集しました。一方で、私は間違っている最小限の例に到達しようとします。 –

答えて

1

SQLサーバの実際のデータが矛盾していることが問題でした。
としては、両方のテーブル内の少なくとも1つの一致があるときINNERキーワード戻り行を結合

thereを述べました。 "Table1"に "Table2"に一致する行がない場合、その行はリストされません。

"Table1"と一致する "Table2"に実際に行がない限り、このクエリが失敗する理由はありません。FK制約は強制されるので、これは奇妙ですが、それは別の質問に値するものです。このケースは閉じられています。

0

私の推測では、()sがあなたのクエリが順番に評価しないために引き起こしているということです期待どおり、TableDateはWhere()が呼び出されたときに使用できません。あなたが評価を強制したら、Where()に電話をかけるとどうなりますか?

関連する問題