c# - 更改 DbSet 类型参数时,EF Core 的行为有所不同
问题描述
我正在使用 EF Core 5.0.5
我有一个数据库,其中包含两个表“t_ErrorLogs_Ciliate_IN”和“t_ErrorLogs_Ciliate_OUT”,它们具有相同的列。一个进程写入其中一个表,另一个进程写入另一个,但记录的结构完全相同,这就是它们具有相同列的原因。
我的 DbContext 看起来像这样:
public class CiliateLoggingContext : DbContext
{
public CiliateLoggingContext() { }
public CiliateLoggingContext(DbContextOptions options) : base(options) { }
public virtual DbSet<ErrorLog_Ciliate_IN> t_ErrorLogs_Ciliate_IN { get; set; }
public virtual DbSet<ErrorLog_Ciliate_OUT> t_ErrorLogs_Ciliate_OUT { get; set; }
}
“ErrorLog_Ciliate_IN”和“ErrorLog_Ciliate_OUT”类只是:
public partial class ErrorLog_Ciliate_IN : CiliateErrorLogBase { }
public partial class ErrorLog_Ciliate_OUT : CiliateErrorLogBase { }
public class CiliateErrorLogBase
{
// properties representing the columns.
}
如果我尝试选择这样的日志:
Task<List<ErrorLog_Ciliate_IN>> SelectMethod()
{
context.t_ErrorLogs_Ciliate_IN.Where(log => log.Id > 10).OrderByDescending(log => log.Id).Take(20).ToListAsync();
}
一切都很好,我得到了一个任务,我等待它,它给了我一个ErrorLogs_Ciliate_IN
对象列表。
极好的!
但是,由于“ErrorLog_Ciliate_IN”和“ErrorLog_Ciliate_OUT”类完全相同,我想创建一个“ErrorLog_Ciliate”类并使用它。
public partial class ErrorLog_Ciliate : CiliateErrorLogBase { }
并将 DbContext 更改为:
public class CiliateLoggingContext : DbContext
{
public CiliateLoggingContext() { }
public CiliateLoggingContext(DbContextOptions options) : base(options) { }
public virtual DbSet<ErrorLog_Ciliate> t_ErrorLogs_Ciliate_IN { get; set; }
public virtual DbSet<ErrorLog_Ciliate> t_ErrorLogs_Ciliate_OUT { get; set; }
}
然而 EF 突然决定从“ErrorLog_Ciliate”中选择,而不是“t_ErrorLogs_Ciliate_IN”。
这就是“ToQueryString()”在 DbContext 的第一个版本中返回的内容 - 每个表都有一个单独的类:
方法:
string SelectIN()
{
context.t_ErrorLogs_Ciliate_IN.Where(log => log.Id > 10).OrderByDescending(log => log.Id).Take(20).ToListAsync();
}
string SelectOUT()
{
context.t_ErrorLogs_Ciliate_OUT.Where(log => log.Id > 10).OrderByDescending(log => log.Id).Take(20).ToListAsync();
}
结果:
DECLARE @__p_0 int = 20;
SELECT TOP(@__p_0) [t].[Id], [t].[Date], [t].[Type]
FROM [t_ErrorLogs_Ciliate_IN] AS [t]
WHERE [t].[Id] > 10
ORDER BY [t].[Id] DESC
DECLARE @__p_0 int = 20;
SELECT TOP(@__p_0) [t].[Id], [t].[Date], [t].[Type]
FROM [t_ErrorLogs_Ciliate_OUT] AS [t]
WHERE [t].[Id] > 10
ORDER BY [t].[Id] DESC
如果我使用 DbContext 的第二个版本,其中两个 DbSet 使用相同的类型参数,ErrorLog_Ciliate
最奇怪的事情会发生:
DECLARE @__p_0 int = 20;
SELECT TOP(@__p_0) [a].[Id], [a].[Data], [a].[Type]
FROM [CiliateErrorLog] AS [a]
WHERE [a].[Id] > 10
ORDER BY [a].[Id] DESC
DECLARE @__p_0 int = 20;
SELECT TOP(@__p_0) [a].[Id], [a].[Data], [a].[Type]
FROM [CiliateErrorLog] AS [a]
WHERE [a].[Id] > 10
ORDER BY [a].[Id] DESC
注意它现在是如何尝试从类的名称中选择的,而之前它是如何尝试从 DbContext 参数的名称中选择的。
如果我使用 DbContext 的混合版本,它具有:
public virtual DbSet<ErrorLog_Ciliate> t_ErrorLogs_Ciliate_IN { get; set; }
public virtual DbSet<ErrorLog_Ciliate_OUT> t_ErrorLogs_Ciliate_OUT { get; set; }
我得到了正常的第一个结果:
DECLARE @__p_0 int = 20;
SELECT TOP(@__p_0) [t].[Id], [t].[Date], [t].[Type]
FROM [t_ErrorLogs_Ciliate_IN] AS [t]
WHERE [t].[Id] > 10
ORDER BY [t].[Id] DESC
DECLARE @__p_0 int = 20;
SELECT TOP(@__p_0) [t].[Id], [t].[Date], [t].[Type]
FROM [t_ErrorLogs_Ciliate_OUT] AS [t]
WHERE [t].[Id] > 10
ORDER BY [t].[Id] DESC
为什么会发生这种情况,我如何对两个属性使用相同的类型参数并且仍然让 EF 识别它应该从属性名称中选择“来自”?
解决方案
EF 仅支持每个实体类型在模型中的一个映射 per DbContext
,因此您不能将相同类型的两个实例映射到同一上下文中的不同表。如果您查看EF Fluent API,您会发现它基于类型而不是DbSet
's. 因此,要在不同的表之间共享表结构,就像您自己已经完成的那样,您需要使用继承 - 最常见的方法是从相同的基类或更深奥的继承实体类型 -在 .inheritDbContext
中的覆盖实体设置OnModelCreating
。
推荐阅读
- sql - 通过 VBA 将值动态传递给 SQL Server
- c++ - Why i can't use Windows Environment path with ofstream to write a text file?
- angularjs - 角砌体选项不起作用
- embedding - 是否可以将 perl6 嵌入到 C(或 C++)程序中?
- android - 使用 CursorAdapter 在 Activity 上设置 ClickListener
- php - PHP MYSQL - 插入一条新记录,但需要另一个表中的 select 语句中的列 - 在 php 中失败
- postgresql - 使用 Postgres 的条件查询
- python-3.x - Docker 将参数传递给使用 argparse 的 python 脚本
- opencv - 多边形感兴趣区域 (ROI)
- windows - 如何读取 WM_PAINT 消息的内容?