简体   繁体   English

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

[英]De-normalizing data into a code first Entity Framework entity, without a SQL View

First, here's a simple example database model, which has Products assigned to Categories , where CategoryId in Products is the FK relationship to Categories . 首先,这里有一个简单的例子数据库模型,其中有Products分配给Categories ,其中CategoryIdProducts是对FK关系Categories

Products : 产品

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

Categories 分类

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

For the .NET application data model, only a de-normalized representation of a Product is defined as an entity class: 对于.NET应用程序数据模型,只将Product非规范化表示定义为实体类:

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

There is no Category class defined, and for this example, none is planned. 没有定义Category类,对于此示例,没有计划任何类。

In the code-first Entity Framework DbContext -derived class, I've setup the DbSet<Product> Products entity set: 在代码优先的Entity Framework DbContext -derived类中,我设置了DbSet<Product> Products实体集:

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

And in the EntityTypeConfiguration , I'm attempting to wire it up, but I'm just not able to get it working right: 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?
    }
}

I realize that a SQL View could be created and then I could tell EF to map to that view using ToTable("App1ProductsView") , but in this example, I'd like to avoid doing so. 我意识到可以创建一个SQL视图然后我可以告诉EF使用ToTable("App1ProductsView")映射到该视图,但在这个例子中,我想避免这样做。

In a SQL ADO.NET ORM solution, there's no issue here. 在SQL ADO.NET ORM解决方案中,这里没有问题。 I can simply write my own SQL statement to perform the INNER JOIN Categories c ON c.CategoryId = p.CategoryId join. 我可以简单地编写自己的SQL语句来执行INNER JOIN Categories c ON c.CategoryId = p.CategoryId join。 How can I use the EF code-first Fluent API to perform this same inner join when populating the entity? 在填充实体时,如何使用EF代码优先Fluent API执行相同的内部联接?

In my research, I've seen a lot of "entity split across multiple tables" topics, but this is not that. 在我的研究中,我看到很多“实体分成多个表格”主题,但事实并非如此。 Categories and Products are two distinct entities (from a database perspective), but the .NET code is meant to stay unaware of that. 类别和产品是两个不同的实体(从数据库的角度来看),但.NET代码意味着不知道这一点。

Failed Attempt 1 : 尝试失败1

This does not work, and produces a strange query (seen with SQL Server Profiler). 这不起作用,并产生一个奇怪的查询(与SQL Server Profiler一起看到)。

Fluent config: 流利的配置:

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

Resulting SQL: 结果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]

Short answer: MS EF6 is not designed for that, you can't do it easily. 简短的回答:MS EF6不是为此设计的,你不能轻易做到。

Please read about the keys , relationships and how to configure one-to-many relationship . 请阅读有关密钥关系以及如何配置一对多关系的信息

EF expects your entity to have a key which is a part of a mapped table. EF希望您的实体拥有一个键,该键是映射表的一部分。 You could use splitting, ie put some properties in Table1 and some to Table2, but only if both tables share the same primary key. 你可以使用分割,即把在表1和部分中的一些属性表2,但前提是两个表共享相同的主键。 That works for [1] -> [0..1] relationships only. 这适用于[1] - > [0..1]关系。 What you have is a one-to-many. 你拥有的是一对多。

EF way of mapping your db schema is to create two entities and access the category name as Product.Category.Name . 映射数据库模式的EF方法创建两个实体并将类别名称作为Product.Category.Name访问。

If you completely do not want to expose Category entity, you may use an internal class and a protected property, exposing category name as a sql-ignored property public string CategoryName => this.Category?.Name . 如果您完全不希望公开Category实体,则可以使用内部类和受保护属性,将类别名称公开为sql-ignored属性public string CategoryName => this.Category?.Name

The other option is to use untracked SqlQuery . 另一种选择是使用未跟踪的SqlQuery Then you will have to write SQL query yourself, as you did for the pure ADO.NET solution. 然后,您将必须自己编写SQL查询,就像您为纯ADO.NET解决方案所做的那样。

If you don't want to use EF change tracking, relationships and etc, consider a lighter ORM like Dapper, linq2db or BLToolkit. 如果您不想使用EF更改跟踪,关系等,请考虑使用更轻的ORM,如Dapper,linq2db或BLToolkit。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM