更改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在每个DbContext的每个实体类型的模型中只支持一个映射,因此不能在同一上下文中将两个相同类型的实例映射到不同的表。如果你查看EF Fluent API,你会发现它是基于类型而不是DbSet的。因此,要在不同的表之间共享表结构,正如您自己所做的那样,您需要使用继承——最常见的方法是从同一基类继承实体类型,或者更深奥的方法是继承DbContextOnModelCreating中的重写实体设置。

最新更新