2013-08-01 27 views
6

Tôi đang sử dụng Khung thực thể để ánh xạ hai bảng với nhau bằng cách sử dụng Phân tách thực thể như được nêu herehere.Tại sao Entity Framework 5 truy vấn các bảng khác nhau khi thực hiện một .ToList() so với một .Count() trên cùng một thực thể?

Tôi đã nhận thấy rằng nếu tôi thực thi một số .ToList() trên IQueryable<SplitEntity> thì kết quả là từ Tham gia bên trong. Tuy nhiên, nếu tôi lấy cùng một IQueryable đó và thực thi một số .Count() nó sẽ trả về số lượng các bản ghi được trả về bởi một Tham gia đầy đủ.

Dưới đây là một thử nghiệm đơn vị đó không:

[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. 
    } 

này đập vào mắt tôi là rất xấu. Làm thế nào tôi có thể nhận được phương thức .Count() để trả lại kết quả từ một Tham gia Nội bộ như .ToList()?

Cập nhật - SQL

Tôi đã sai về sự tham gia đầy đủ so với bên trong.

Các ToList() kết quả trong:

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] 

Các Count() kết quả trong:

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

Update - DataContext và thực thể đang

Các 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()); 
     } 
    } 
} 

Quy trình giám sát omer Mapping (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"); 
       }); 
    } 
} 

Thực thể của khách hàng:

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

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

Bạn chưa cho chúng ta thấy các truy vấn nó tạo ra ... –

+0

chúng ta cần xem ngữ cảnh. Khách hàng cần biết nhiều hơn. Nếu bạn thực hiện một truy vấn đơn giản thì bạn sẽ nhận được cùng một số tôi nghĩ. – phillip

+0

Câu hỏi đã được cập nhật với mã ngữ cảnh và thực thể bổ sung. – quakkels

Trả lời

5

Nếu cơ sở dữ liệu và tất cả các bản ghi trong CustomerTable1CustomerTable2 đã được tạo ra bởi Entity Framework và SaveChanges cuộc gọi trong mã ứng dụng của bạn sự khác biệt này không phải xảy ra và bạn có thể đi thẳng về phía trước và report this as a bug.

Nếu bạn đang ánh xạ tới cơ sở dữ liệu hiện có hoặc nếu các ứng dụng khác ghi bản ghi vào bảng và bạn thực sự mong rằng không phải mọi bản ghi trong CustomerTable1 đều có một bản ghi tương ứng trong CustomerTable2 và ngược lại thì Phân tách thực thể là ánh xạ sai cơ sở dữ liệu của bạn lược đồ.

Rõ ràng sự khác biệt có nghĩa là bạn có thể có Customer s với CustomerNumber (v.v.), nhưng không có CustomerName (v.v) - hoặc cách khác. Cách tốt hơn để lập mô hình này sẽ là mối quan hệ một-một trong đó một bên là bắt buộc và phía bên kia là tùy chọn. Bạn sẽ cần một thực thể bổ sung và một tài sản chuyển hướng cho điều này, ví dụ như vậy:

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

Với bản đồ API thạo này:

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

Đây là cơ sở dữ liệu hiện có với cấu trúc bảng hiện có. Nhưng lớp 'Customer' của tôi là sự kết hợp của hai bảng. Các bản ghi có thể tồn tại trong 'CustomerTable2' không tồn tại trong' CustomerTable1'. NHƯNG thực thể 'Khách hàng' thực sự chỉ tồn tại khi các bản ghi đó trùng lặp. Đây là tất cả theo các quy tắc hiện tại của cơ sở dữ liệu này mà tôi cần phải làm việc bên trong. Ngay cả với thực tế này, nó tấn công tôi rằng nếu '.Count()' sử dụng một truy vấn khác với '.ToList()' thì điều này nên được coi là một lỗi. – quakkels

+3

@quakkels: Tôi hiểu đối số và khiếu nại của bạn. Mặt khác, sử dụng truy vấn 'Count' trên chỉ một trong các bảng là loại tối ưu hóa hiệu suất, vì JOIN không cần thiết * theo giả định * rằng các bản ghi trong 2 bảng có quan hệ một-một-một chặt chẽ đó, tôi tin rằng, là một giả thiết mà EF tạo ra khi sử dụng tính năng tách thực thể. Ngoài ra, tôi nghĩ, việc sử dụng INNER JOIN là một quyết định dựa trên cùng một giả định. Mục đích của nó là không lọc ra các khách hàng không có dữ liệu trong * cả hai * bảng. Tôi sẽ xem xét để báo cáo tại CodePlex và xem những gì đội EF nói. – Slauma

1

tôi truy vấn một bảng địa phương và tôi lấy số liệu tương tự cho cả hai. Tôi tin rằng có một vấn đề với bối cảnh của bạn và đó là lý do tại sao kết quả của bạn không phù hợp.

ảnh chụp màn hình về cơ bản cùng một mã chỉ truy vấn một tập dữ liệu đơn giản.

enter image description here

UPDATE:

Tôi không biết lý do tại sao SQL được tạo ra là khác nhau. Bạn sẽ nghĩ rằng chúng sẽ giống nhau, ngoại trừ việc chỉ thực hiện Count (*) thay vì trả về tất cả các hàng. Đó rõ ràng là lý do tại sao bạn đang nhận được một số lượng khác nhau. Tôi không thể nói tại sao SQL lại khác.

Có thể Jon Skeet hoặc thiên tài khác sẽ thấy câu trả lời này! :)

+0

Đây không phải là một bảng duy nhất. Một thực thể này 'Customer' được ánh xạ tới HAI bảng bằng cách sử dụng tách thực thể. Nó được thảo luận [ở đây] (http://stackoverflow.com/questions/6670580/mapping-multiple-tables-to-a-single-entity-class-in-entity-framework) và [ở đây] (http: // msdn.microsoft.com/en-us/magazine/hh126815.aspx). – quakkels

+0

Tôi sẽ thêm nhiều mã hơn vào câu hỏi của mình. Có lẽ điều đó sẽ giúp :-) – quakkels

Các vấn đề liên quan