我在 ASP.NET Core 3.1 应用程序中使用 Entity Framework Core 5.0(这是将现有 .NET Framework 应用程序迁移到 .NET Core 的一部分)。我将 POCO 定义如下:
public class Message
{
public Guid MessageId { get; set; }
public MessageDispatcherRoute RouteInfo { get; set; }
public MessageDispatcherRoute ReturnRouteInfo { get; set; }
public List<MessageResponse> Responses { get; set; }
// other properties
}
public class MessageDispatcherRoute
{
public string Url { get; set; }
public string HttpVerb { get; set; }
}
public class MessageResponse
{
public Guid MessageId { get; set; }
public int ResponseNumber { get; set; }
// other properties
}
表架构如下所示 (SQL Server 13.0):
CREATE TABLE [Message] (
[MessageId] UNIQUEIDENTIFIER NOT NULL PRIMARY KEY,
[RouteInfo_Url] VARCHAR(255),
[RouteInfo_HttpVerb] VARCHAR(10),
[ReturnRouteInfo_Url] VARCHAR(255),
[ReturnRouteInfo_HttpVerb] VARCHAR(10),
-- other columns
}
-- MessageResponse is a separate table
根据Microsoft documentation on owned types ,我应该能够使用显式声明来完成此操作(这是第一个示例),因此我的模型构建器看起来像这样(当前状态;我仍在迁移站点中):
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.RemovePluralizingTableNameConvention(); // https://stackoverflow.com/questions/37493095/entity-framework-core-rc2-table-name-pluralization
modelBuilder.Entity<App>().HasKey(x => x.AppId);
modelBuilder.Entity<App>().HasMany(x => x.AppSettings);
modelBuilder.Entity<CustomQueue>().HasKey(x => x.CustomQueueId);
modelBuilder.Entity<Message>().HasKey(m => m.MessageId);
modelBuilder.Entity<Message>().OwnsOne(m => m.RouteInfo);
modelBuilder.Entity<Message>().OwnsOne(m => m.ReturnRouteInfo);
modelBuilder.Entity<MessageResponse>().HasKey(m => new { m.MessageId, m.ResponseNumber });
modelBuilder.Entity<Message>().HasMany(m => m.Responses);
}
所有这些都连接到 OData Controller :
public class MessagesController : Controller
{
private readonly IMyContext _context;
public MessagesController(IMyContext context)
{
_context = context;
}
[HttpGet]
[EnableQuery(MaxExpansionDepth = 1)]
public IQueryable<Message> Get(ODataQueryOptions options)
{
return _context.Messages.AsQueryable().Include(x => x.Responses).AsSingleQuery();
}
}
问题是,当我使用查询字符串 $top=5
访问 OData 端点时,出现异常:SqlException: Invalid object name 'MessageDispatcherRoute'。
SQL Profiler,我可以看到 EF 正在尝试连接到一个不存在的表(注意:为简洁起见,省略了不相关的列)。
exec sp_executesql N'SELECT [t].[MessageId]
, [m1].[MessageId], [m1].[RouteInfo_HttpVerb], [m1].[RouteInfo_Url]
, [m0].[MessageId], [m2].[MessageId], [m2].[ResponseNumber]
FROM (
SELECT TOP(@__TypedProperty_0) [m].[MessageId]
, [m].[ReturnRouteInfo_HttpVerb], [m].[ReturnRouteInfo_Url]
FROM [Message] AS [m]
ORDER BY [m].[MessageId]
) AS [t]
LEFT JOIN [MessageDispatcherRoute] AS [m0] ON [t].[MessageId] = [m0].[MessageId]
LEFT JOIN [MessageDispatcherRoute] AS [m1] ON [t].[MessageId] = [m1].[MessageId]
LEFT JOIN [MessageResponse] AS [m2] ON [t].[MessageId] = [m2].[MessageId]
ORDER BY [t].[MessageId], [m0].[MessageId], [m1].[MessageId], [m2].[MessageId], [m2].[ResponseNumber]'
,N'@__TypedProperty_0 int',@__TypedProperty_0=5
我尝试在模型构建器中显式设置列名称,如EF Core 2.2, owned entities generated as another table when multiple in hierarchy所示,但这没有改变任何事情。
更新:我制作了一个控制台应用程序,除了一个精简的 DbContext 之外什么都没有,上面显示的 3 个 POCO 没有帮助。如果我将 [Owned]
添加到 MessageDispatcherRoute 类,则会产生非常奇怪的输出:
LEFT JOIN [Message.ReturnRouteInfo#MessageDispatcherRoute] AS [m0] ON [t].[MessageId] = [m0].[MessageID]
LEFT JOIN [Message.RouteInfo#MessageDispatcherRoute] AS [m1] ON [t].[MessageId] = [m1].[MessageID]
LEFT JOIN [Message.ReturnRouteInfo#MessageDispatcherRoute] AS [m2] ON [t].[MessageId] = [m2].[MessageID]
我做错了什么?谢谢。
最佳答案
在尝试随机操作看看会发生什么之后,解决方案是将拥有的类型映射回同一个表,即使 the documentation根本不提供此信息。事实上,它明确表示只有当拥有的类型位于单独的表中时才需要这样做。
modelBuilder.Entity<Message>().OwnsOne(m => m.RouteInfo, mdr => mdr.ToTable(nameof(Message)));
modelBuilder.Entity<Message>().OwnsOne(m => m.ReturnRouteInfo, mdr => mdr.ToTable(nameof(Message)));
关于c# - 使用拥有的类型时,Entity Framework Core 尝试连接到不存在的表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65912653/