6

我正在使用实体框架将两个表映射在一起,使用此处此处概述的实体拆分。

我发现如果我执行 a .ToList()on anIQueryable<SplitEntity>则结果来自 Inner Join。但是,如果我采用相同的 IQueryable 并执行 a .Count(),它将返回 Full Join 返回的记录数。

这是一个失败的单元测试:

    [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()从内部联接返回结果的方法,例如.ToList()

更新 - SQL

我对完整与内部联接的看法是错误的。

.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 和实体代码

数据上下文:

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

客户映射(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; }
}
4

2 回答 2

5

如果数据库和所有记录都由 Entity Framework 创建并CustomerTable1在您的应用程序代码中调用,则不能出现这种差异,您可以直接将其报告为错误CustomerTable2SaveChanges

如果您正在映射到现有数据库,或者如果其他应用程序将记录写入表中,并且您实际上希望并非每条记录CustomerTable1都有相应的记录,CustomerTable2反之亦然,那么实体拆分是您的数据库模式的错误映射。

显然,差异意味着您可以将Customers 与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
}

使用这个 Fluent API 映射:

public class CustomerMapping : EntityTypeConfiguration<Customer>
{
    public CustomerMapping()
    {
        this.HasOptional(c => c.AdditionalCustomerData)
            .WithRequired()
            .WillCascadeOnDelete(true);
    }
}
于 2013-08-04T20:09:21.950 回答
1

我正在查询一个本地表,并且两者的计数相同。我相信您的上下文存在问题,这就是您的结果不一致的原因。

只是查询一个简单数据集的基本相同代码的屏幕截图。

在此处输入图像描述

更新:

我不知道为什么生成的 SQL 不一样。您会认为它们是相同的,只是简单地执行 Count(*) 而不是返回所有行。这显然是为什么你得到不同的计数。我只是不能说为什么 SQL 是不同的。

也许 Jon Skeet 或其他天才会看到这个并回答!:)

于 2013-08-01T21:05:08.567 回答