简体   繁体   English

Entity Framework Core 在使用自有类型时尝试加入不存在的表

[英]Entity Framework Core tries to join to a non-existent table when using an owned type

I'm using Entity Framework Core 5.0 in a ASP.NET Core 3.1 application (this is part of migrating an existing .NET Framework application to .NET Core).我在 ASP.NET Core 3.1 应用程序中使用 Entity Framework Core 5.0(这是将现有 .NET 框架应用程序迁移到 .NET 核心的一部分)。 I have POCOs defined as such:我有这样定义的 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
}

The table schema looks like this (SQL Server 13.0):表架构如下所示(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

According to the Microsoft documentation on owned types , I should be able to use explicit declaration to accomplish this (it's the very first example), so my model builder looks like this (current state; I'm still in the middle of migrating the site):根据有关拥有类型的 Microsoft 文档,我应该能够使用显式声明来完成此操作(这是第一个示例),因此我的 model 构建器看起来像这样(当前 state;我仍在迁移站点):

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);
}

All this is hooked to an OData controller:所有这些都与 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(); 
    }
}

The problem is when I hit the OData endpoint with the query string $top=5 , I get an exception saying SqlException: Invalid object name 'MessageDispatcherRoute'.问题是,当我使用查询字符串$top=5访问 OData 端点时,我得到一个异常说SqlException: Invalid object name 'MessageDispatcherRoute'. Using SQL Profiler, I can see that EF is trying to join to a non-existent table (note: unrelated columns omitted for brevity).使用 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

I tried explicitly setting the column names in the model builder, as shown in EF Core 2.2, owned entities generated as another table when multiple in hierarchy , but that changed nothing.我尝试在 model 构建器中显式设置列名,如EF Core 2.2 所示,拥有的实体在多个层次结构中生成为另一个表,但这没有任何改变。

UPDATE: I've made a console application with nothing but a stripped-down DbContext and the 3 POCOs shown above didn't help.更新:我已经制作了一个控制台应用程序,只有一个精简的 DbContext,上面显示的 3 个 POCO 没有帮助。 If I add [Owned] to the MessageDispatcherRoute class, that results in a really weird output:如果我将[Owned]添加到 MessageDispatcherRoute class,则会导致非常奇怪的 output:

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]

What am I doing wrong?我究竟做错了什么? Thanks.谢谢。

The problem might be that you are missing a call to .WithOwner() after calling .OwnsOne() .问题可能是您在调用.OwnsOne() .WithOwner()之后错过了对 .WithOwner() 的调用。

From the docs :文档

Configures a relationship where the target entity is owned by (or part of) this entity.配置目标实体由该实体拥有(或属于该实体的一部分)的关系。

The target entity type for each ownership relationship is treated as a different entity type even if the navigation is of the same type.即使导航属于同一类型,每个所有权关系的目标实体类型也被视为不同的实体类型。 Configuration of the target entity type isn't applied to the target entity type of other ownership relationships.目标实体类型的配置不适用于其他所有权关系的目标实体类型。

Most operations on an owned entity require accessing it through the owner entity using the corresponding navigation.对拥有实体的大多数操作都需要通过拥有者实体使用相应的导航来访问它。

After calling this method, you should chain a call to WithOwner(String) to fully configure the relationship.调用此方法后,您应该链接调用 WithOwner(String) 以完全配置关系。

So, in your case, you could try something like this:所以,在你的情况下,你可以尝试这样的事情:

modelBuilder.Entity<Message>().OwnsOne(m => m.RouteInfo).WithOwner();
modelBuilder.Entity<Message>().OwnsOne(m => m.ReturnRouteInfo).WithOwner();

You might need to add a migration after this, but I think you don't since your DB schema is already okay.在此之后您可能需要添加迁移,但我认为您不需要,因为您的数据库架构已经可以了。

After just trying random things to see what would happen, the solution was to map the owned type back to the same table, even though the documentation does not give this information at all.在尝试随机事情以查看会发生什么之后,解决方案是将 map 拥有的类型返回到同一个表,即使文档根本没有提供此信息。 In fact, it specifically says this is only required when the owned types are in a separate table.事实上,它明确表示只有当拥有的类型在单独的表中时才需要这样做。

modelBuilder.Entity<Message>().OwnsOne(m => m.RouteInfo, mdr => mdr.ToTable(nameof(Message)));
modelBuilder.Entity<Message>().OwnsOne(m => m.ReturnRouteInfo, mdr => mdr.ToTable(nameof(Message)));

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

相关问题 实体框架核心 - 拥有类型的修改键 - Entity Framework Core - Modified key on owned type Entity Framework Core 2 拥有的实体类型 - 更改表列的名称 - Entity Framework Core 2 Owned Entity Types - Change Names of Table Columns 实体框架核心设置在添加时拥有实体null - Entity Framework Core setting owned entity null when added Entity Framework Core:具有导航属性的自有类型 - Entity Framework Core: Owned type that has navigation properties 实体框架6尝试在重命名时删除不存在的索引 - Entity Framework 6 trying to drop non existent Index when renaming EF 核心 3.1 - 实体和拥有类型的公共表 - EF core 3.1 - common table for entity and owned type 如何使用 Entity Framework Core 创建连接表? - How to make a join table using Entity Framework Core? 与 IdentityUser 一起使用时,Entity Framework Core 拥有的类型值 Object 抛出 required Primary Key to be defined 错误。 为什么? - Entity Framework Core Owned Type Value Object throws required Primary Key to be defined error when used with IdentityUser. Why? LINQ生成错误的SQL(对不存在的表的引用) - LINQ generates incorrect SQL (reference to a non-existent table) C# 尝试删除不存在的文件夹时崩溃 - C# crashes when trying to delete non-existent folder
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM