c# - 使用拥有的类型时,Entity Framework Core 尝试连接到不存在的表

标签 c# entity-framework asp.net-core entity-framework-core odata

我在 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/

相关文章:

c# - 序列化实体对象

c# - 使用 EF 检查表中新记录的成本最低的操作

unit-testing - Visual Studio 2015 RC1 Update 1 中的 XUnit 找不到测试

asp.net-core - 如何配置 ASP.NET Core 多微服务应用程序和 Azure AKS 入口路由,使其不会破坏 wwwroot 文件夹中的资源

c# - 在 Ubuntu 上使用 VSCode 编译 C# 项目

c# - 通用单例<T>

c# - 更改 DataGridViewButtonCell 值时发生 StackOverflowException

entity-framework - Entity Framework 代码优先 : Initializing a Database using Console Application

c# - 强制在属性上使用一个属性,如果它们已经有另一个属性

asp.net-core - .NET core 中 messageBox 的类似方法