c# - 将数据反规范化为代码优先的实体框架实体,无需 SQL 视图
问题描述
首先,这是一个简单的示例数据库模型,它已Products
分配给Categories
,其中CategoryId
inProducts
是与 的 FK 关系Categories
。
产品:
- 产品 ID (PK), INT
- 产品名称 VARCHAR(255)
- 类别 ID (FK), INT
类别
- 类别 ID (PK), INT
- 类别名称 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; }
}
没有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]
解决方案
简短的回答: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。
推荐阅读
- javascript - 失去焦点时提交表单
- mysql - 选择哪个用户有更多产品
- c# - 如何从 Azure Function App 中的请求正文中检索字节数据
- rxjs - 无法从 rxjs 5.0 取消 observable
- java - 自定义 Maven 插件 - 阅读 maven-metadata.xml?
- gradle - 如何在 Gradle Kotlin DSL 中使用类型安全的额外属性
- amazon-web-services - 当 ECS 中有多个仅在命令上有所不同的服务时,如何避免 terraform 中的重复?
- android - Cipher.doFinal 之后的 Android AES 加密丢失字节
- r - Shiny中的对象问题
- html - Css - 移动设备上的图像被破坏