2013-08-01 59 views
6

我正在使用實體框架來使用實體分割將兩個表映射到一起,如概述herehere爲什麼實體框架5在同一實體上執行.ToList()與.Count()時查詢不同的表?

我發現如果我在IQueryable<SplitEntity>上執行.ToList(),則結果來自Inner Join。但是,如果我採用相同的IQueryable並執行.Count(),它將返回完全連接返回的記錄數。

這是一個單元測試失敗:

[TestMethod] 
    public void GetCustomerListTest() 
    { 
     // arrange 
     List<Customer> results; 
     int count; 

     // act 
     using (var context = new DataContext()) 
     { 
      results = context.Customers.ToList(); 
      count = context.Customers.Count(); 
     } 

     // assert 
     Assert.IsNotNull(results); // succeeds 
     Assert.IsTrue(results.Count > 0); // succeeds. Has correct records from inner join 
     Assert.AreEqual(count, results.Count); // This line fails. Has incorrect count from full join. 
    } 

這令我非常糟糕。我怎樣才能讓.Count()方法返回來自Inner Join的結果,如.ToList()

更新 - SQL

我對完整vs內連接錯了。

的.ToList()的結果:

SELECT 
    [Extent1].[CustomerNumber] AS [CustomerNumber], 
    -- ...etc... 
    [Extent2].[CustomerName] AS [CustomerName], 
    -- ... etc... 
    FROM [dbo].[CustomerTable1] AS [Extent1] 
    INNER JOIN [dbo].[CustomerTable2] AS [Extent2] ON [Extent1].[CustomerNumber] = [Extent2].[CustomerNumber] 

的.Count之間()的結果:

SELECT 
[GroupBy1].[A1] AS [C1] 
FROM (SELECT 
    COUNT(1) AS [A1] 
    FROM [dbo].[customerTable2] AS [Extent1] 
) AS [GroupBy1] 

更新 - 的DataContext和實體代碼

在DataContext:

public class DataContext : DbContext 
    { 
     public DataContext() { Database.SetInitializer<DataContext>(null); } 

     public DbSet<Customer> Customers { get; set; } 

     protected override void OnModelCreating(DbModelBuilder modelBuilder) 
     { 
      base.OnModelCreating(modelBuilder); 

      modelBuilder.Configurations.Add(new CustomerMapping()); 
     } 
    } 
} 

The Cust奧馬爾映射(FluentAPI):

public class CustomerMapping : EntityTypeConfiguration<Customer> 
{ 
    public CustomerMapping() 
    { 
     this.Map(m => { 
        m.Properties(x => new { x.CustomerNumber, /*...etc...*/}); 
        m.ToTable("CustomerTable1"); 
       }) 
     .Map(m => { 
        m.Properties(x => new { x.CustomerName, /*...etc...*/}); 
        m.ToTable("CustomerTable2"); 
       }); 
    } 
} 

客戶實體:

public class Customer 
{ 
    [Key] 
    public string CustomerNumber { get; set; } 

    public string CustomerName { get; set; } 
} 
+1

你還沒有告訴我們它生成的查詢... –

+0

我們需要了解情況。客戶需要了解更多信息。如果你執行一個簡單的查詢,那麼你會得到相同的計數,我認爲。 – phillip

+0

該問題已更新爲附加的上下文和實體代碼。 – quakkels

回答

5

如果數據庫和CustomerTable1CustomerTable2所有記錄已經由實體框架創建,並在應用程序代碼中調用SaveChanges這種差異應該不會發生,你可以直行和report this as a bug

如果你映射到一個現有的數據庫或者其他應用程序寫入記錄到表,你居然想到的是不是CustomerTable1每條記錄​​在CustomerTable2相應的記錄,反之則實體分割是數據庫的錯誤映射架構。

顯然差異意味着你可以有Customer s與CustomerNumber(等),但沒有CustomerName(等) - 或相反的方式。建模的更好方法是一對一關係,其中一方是必需的,另一方是可選的。您將需要一個額外的實體和導航屬性這一點,比如像這樣:

[Table("CustomerTable1")] 
public class Customer 
{ 
    [Key] 
    public string CustomerNumber { get; set; } 
    // + other properties belonging to CustomerTable1 

    public AdditionalCustomerData AdditionalCustomerData { get; set; } 
} 

[Table("CustomerTable2")] 
public class AdditionalCustomerData 
{ 
    [Key] 
    public string CustomerNumber { get; set; } 
    public string CustomerName { get; set; } 
    // + other properties belonging to CustomerTable2 
} 

有了這個良好的API映射:

public class CustomerMapping : EntityTypeConfiguration<Customer> 
{ 
    public CustomerMapping() 
    { 
     this.HasOptional(c => c.AdditionalCustomerData) 
      .WithRequired() 
      .WillCascadeOnDelete(true); 
    } 
} 
+0

這是一個現有的數據庫與現有的表結構。但是我的'客戶'類是兩個表的組合。記錄可以存在於CustomerTable1中不存在的CustomerTable2中。但只有當這些記錄重疊時纔會存在實際的「客戶」實體。這都是根據我需要在這個數據庫中工作的現有規則。即使有這樣的現實,它讓我感到如果'.Count()'使用不同於'.ToList()'的查詢,這應該被認爲是一個錯誤。 – quakkels

+3

@quakkels:我理解你的觀點和抱怨。另一方面,僅在其中一個表上使用「Count」查詢是一種性能優化,因爲JOIN不是必須的*在假設下* 2表中的記錄是嚴格的一對一關係我相信這是EF在使用實體分割時所做的假設。另外,我認爲,INNER JOIN的使用是基於相同假設的決定。目的不是要過濾掉* *表中沒有數據的客戶。我會考慮在CodePlex上報告,看看EF團隊說了些什麼。 – Slauma

1

我查詢本地表和我獲得相同的計數兩者。我相信你的背景有問題,這就是你的結果不一致的原因。

本質上相同的代碼只是查詢簡單的數據集的截圖。

enter image description here

UPDATE:

我不知道這是爲什麼生成的SQL是不同的。你會認爲它們會一樣,只是簡單地執行Count(*)而不是返回所有的行。這顯然是你爲什麼會得到不同的結論。我只是不能說爲什麼SQL是不同的。

也許Jon Skeet或其他天才會看到這個並回答! :)

+0

這不是一張表。這一個實體'Customer'使用實體分割映射到兩個表。這是討論[這裏](http://stackoverflow.com/questions/6670580/mapping-multiple-tables-to-a-single-entity-class-in-entity-framework)和[這裏](http:// msdn.microsoft.com/en-us/magazine/hh126815.aspx)。 – quakkels

+0

我會在我的問題中添加更多代碼。也許這將有助於:-) – quakkels