首页 > 解决方案 > 将数据反规范化为代码优先的实体框架实体,无需 SQL 视图

问题描述

首先,这是一个简单的示例数据库模型,它已Products分配给Categories,其中CategoryIdinProducts是与 的 FK 关系Categories

产品

类别

对于 .NET 应用程序数据模型,仅将 a 的非规范化表示Product定义为实体类:

public class Product
{
    public int ProductId { get; set; }
    public string ProductName { get; set; }
    public int CategoryId { get; set; }
    public string CategoryName { get; set; }
}

没有Category定义类,对于这个例子,没有计划。

在代码优先的实体框架DbContext派生类中,我设置了DbSet<Product> Products实体集:

    public virtual DbSet<Product> Products { get; set; }

在 中EntityTypeConfiguration,我正在尝试将其连接起来,但我无法使其正常工作:

public class ProductConfiguration : EntityTypeConfiguration<Product>
{
    public ProductConfiguration()
    {
        HasKey(t => t.ProductId);

        // How do I instruct EF to pull just the column 'CategoryName'
        // from the FK-related Categories table?
    }
}

我意识到可以创建一个 SQL 视图,然后我可以告诉 EF 使用 映射到该视图ToTable("App1ProductsView"),但在此示例中,我想避免这样做。

在 SQL ADO.NET ORM 解决方案中,这里没有问题。我可以简单地编写自己的 SQL 语句来执行INNER JOIN Categories c ON c.CategoryId = p.CategoryId连接。在填充实体时,如何使用 EF 代码优先 Fluent API 执行相同的内部联接?

在我的研究中,我看到了很多“实体拆分为多个表”的主题,但事实并非如此。类别和产品是两个不同的实体(从数据库的角度来看),但 .NET 代码意味着不知道这一点。

尝试 1 失败

这不起作用,并产生一个奇怪的查询(使用 SQL Server Profiler 看到)。

流畅的配置:

Map(m =>
{
    m.Property(t => t.CategoryName);
    m.ToTable("Categories");
});

生成的 SQL:

SELECT 
    [Extent1].[ProductId] AS [ProductId], 
    [Extent2].[ProductName] AS [ProductName], 
    [Extent2].[CategoryId] AS [CategoryId], 
    [Extent1].[CategoryName] AS [CategoryName], 
FROM  [dbo].[Categories] AS [Extent1]
INNER JOIN [dbo].[Product1] AS [Extent2] ON [Extent1].[ProductId] = [Extent2].[ProductId]

标签: c#.netsql-serverentity-frameworkentity-framework-6

解决方案


简短的回答:MS EF6 不是为此而设计的,你不能轻易做到。

请阅读关系以及如何配置一对多关系

EF 希望您的实体有一个键,该键是映射表的一部分。您可以使用拆分,即在 Table1 中放置一些属性,在 Table2 中放置一些属性,但前提两个表共享相同的主键。这仅适用于 [1] -> [0..1] 关系。你所拥有的是一对多。

EF 映射您的数据库架构的方式创建两个实体并将类别名称访问为Product.Category.Name.

如果您完全不想公开Category实体,您可以使用内部类和受保护的属性,将类别名称公开为sql-ignored属性public string CategoryName => this.Category?.Name

另一种选择是使用未跟踪的 SqlQuery。然后您必须自己编写 SQL 查询,就像您为纯 ADO.NET 解决方案所做的那样。

如果您不想使用 EF 更改跟踪、关系等,请考虑使用更轻的 ORM,例如 Dapper、linq2db 或 BLToolkit。


推荐阅读