2012-05-10 19 views
6

Używam EntityFramework 4 + generowane POCO z Lazy ładowanie wyłączone.
Załóżmy, że istnieją tabele SQL o nazwach Tabela 1, Tabela 2, Tabela 3 i Tabela 4 i zakładają, że zawierają pewne dane.
Załóżmy uproszczona reprezentacja POCO z tych tabel wygląda następująco:Zapytanie nie zwracające nic, gdy są dane w bazie danych

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; 
} 

Jeżeli następujący kod będzie wykonywany:

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

EF wygeneruje następującą instrukcję SQL:

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' 

, a zapytanie zwróci oczekiwane dane.
Jednak jeśli poniższy kod będzie wykonywany:

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

EF wygeneruje następujący 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' 

a zapytanie byłoby nic powrotu.

Dlaczego tak się mogło stać?

EDIT

Poniżej przedstawiono SQL do tworzenia powyższych tabelach:

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

To zapytanie będzie również zwracać żadnych rekordów i może służyć jako minimalną przykład :

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

Generated 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' 

Dodatkowo, jest tu wyciąg z .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

Coś jest przekonujące EF potrzebuje połączenia 'INNER' zamiast' LEFT' od 'Table1' do' Table2'. Czy możesz nam powiedzieć więcej o schemacie sql, lub dojść do minimalnego przykładu, który idzie źle? – AakashM

+0

Proszę pokazać mapowanie, którego używasz. –

+0

Edytowałem pytanie za pomocą instrukcji SQL, aby utworzyć powyższe tabele. W międzyczasie postaram się dotrzeć do minimalnego przykładu, który idzie źle. –

Odpowiedz

1

Wygląda na to, że problem polegał na niespójności danych rzeczywistych na serwerze SQL.
Jak stwierdzono there,

wewnętrznej DOŁĄCZ słów kluczowych wierszy zwracanych gdy istnieje co najmniej jeden mecz w obu tabelach. Jeśli istnieją wiersze w "Tabela 1", które nie mają dopasowań w "Tabela 2", te wiersze NIE będą wyświetlane.

nie ma powodu, aby to zapytanie zakończyło się niepowodzeniem, chyba że naprawdę nie ma wiersza w "Tabela 2", który pasuje do "Tabeli 1".To dziwne jednak, ponieważ ograniczenia FK są egzekwowane, ale to zasługuje na kolejne pytanie i ta sprawa jest zamknięta.

0

Domyślam się, że include() s powodują zapytanie nie oceniać w kolejności można się spodziewać, więc TableDate nie jest dostępna, gdy wywoływana jest funkcja Where(). Co jeśli wymusisz ocenę, a następnie zadzwonisz do Where()?

Powiązane problemy