将数据去规范化为代码第一个实体框架实体,没有SQL视图

rya*_*net 5 .net c# sql-server entity-framework entity-framework-6

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

产品:

  • ProductId(PK),INT
  • ProductName VARCHAR(255)
  • CategoryId(FK),INT

分类

  • CategoryId(PK),INT
  • CategoryName VARCHAR(255)

对于.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; }
}
Run Code Online (Sandbox Code Playgroud)

没有Category定义类,对于此示例,没有计划任何类.

在代码优先的Entity Framework DbContext-derived类中,我设置了DbSet<Product> Products实体集:

    public virtual DbSet<Product> Products { get; set; }
Run Code Online (Sandbox Code Playgroud)

而在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?
    }
}
Run Code Online (Sandbox Code Playgroud)

我意识到可以创建一个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");
});
Run Code Online (Sandbox Code Playgroud)

结果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]
Run Code Online (Sandbox Code Playgroud)

小智 4

简短的回答:MS EF6 不是为此而设计的,您无法轻松做到这一点。

请阅读有关键关系以及如何配置一对多关系的信息。

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

EF 映射数据库模式的方法创建两个实体并以Product.Category.Name.

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

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

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