繁体   English   中英

Entity Framework Core 生成列名不明确的 SQL

[英]Entity Framework Core Generating SQL With Ambiguous Column Names

我正在使用 Entity Framework Core 2.2.6。 如果它最终成为一堵文字墙,我将尝试使这个问题简明扼要并提前道歉。 我看到的错误是 SQL Entity Framework Core 生成的一个不明确的列名。

所以我的情况是这样的:我有两个具有多对一关系的实体。 “父”实体实现一个接口,该接口具有 IChildEntity 类型的属性。 以下是接口:

public interface IParentEntity
{
    IChildEntity Child { get; set; }
    string Prop1 { get; set; }
    string Prop2 { get; set; }
}

public interface IChildEntity
{
    string ChildProp1 { get; set; }
    string ChildProp2 { get; set; } 
}

我正在使用 ef core 的 fluent api,为了建立父子之间的关系,我使用了 ChildEntity 的具体类型并定义了 IChildEntity 属性以符合接口,并将事物传递给具体类型:

public class ChildEntity : IChildEntity
{
    public long ID {get; set;}
    public string ChildProp1 { get; set; }
    public string ChildProp2 { get; set; }  
}

public class ParentEntity : IParentEntity
{
    public long ID { get; set; }
    public string Prop1 { get; set; }
    public string Prop2 { get; set; }
    public long ChildID { get; set; }
    // Navigation property so EF Core can create the relationship
    public ChildEntity MappedChild { get; private set; }

    // this is to adhere to the interface
    // just pass this through to the backing concrete instance
    [NotMapped]
    public IChildEntity Child
    {
        get => MappedChild;
        set => MappedChild = (ChildEntity)value;
    }   
}

Then in OnModelCreating I set up the relationship like so:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
   modelBuilder.Entity<ParentEntity>()
        .HasOne(e => e.MappedChild)
        .WithMany()
        .HasForeignKey(e => e.ChildID);
}

这有效并且关系按预期设置,但是我发现当我执行查询时它可以生成一些 SQL,这可能会导致某些数据库引擎中的列错误不明确。 这是示例查询:

MyContext.ParentEntity
.Include(p => p.MappedChild)
.Where(p => p.Prop1.Equals("somestring")
.FirstOrDefault()

生成的 SQL 类似于:

SELECT p."ID", p."ChildID", p."Prop1", p."Prop1", "p.MappedChild"."ID", "p.MappedChild"."ChildProp1", "p.MappedChild"."ChildProp2"
FROM "ParentEntity" AS p
INNER JOIN "ChildEntity" AS "p.MappedChild" ON p."ChildID" = "p.MappedChild"."ID"
WHERE p."Prop1" = 'somestring'
ORDER BY "p.MappedChild"."ID"
LIMIT 1

这里的问题是我们选择了名称为 ID 而不是别名的两列。 一些数据库可以接受,但有些数据库不行。 我可以为此做的一个解决方法是执行两个单独的查询来获取实体和子实体:

var parent = MyContext.ParentEntity
            .Where(p => p.Prop1.Equals("somestring")
            .FirstOrDefault()
MyContext.Entry(parent).Reference(p => s.MappedChild).Load();

但这并不理想,因为它执行多个查询,并且比仅使用 Include() 更不优雅

因为这似乎是一个常见的用例,而且我找不到针对 EF Core 的此类行为的任何错误报告,所以我怀疑我在这里做错了什么,导致 EFCore 没有为这种类型的列名设置别名询问。 我在想这可能是我必须做的一些技巧,以确保我的实体实现它的接口(由于代码库和其他集成中的限制,我无法做到这一点)但我越看它就越不可能在我看来,因为我们直接处理 EF 相关代码中的“映射”属性,并且它完全不知道接口。

我的问题是 - 任何人都可以在我的实现中看到会导致这种情况的东西吗? 谁能提出比我在这里更好的解决方法? 任何建议在这里将不胜感激。 非常感谢。

这是一个旧的实体框架错误,包含 Oracle 公司产品错误,包括 MySQL 数据库和 Oracle 数据库(12.1 及更早版本)。

我看到了

ORA-00918: 列定义不明确

错误主要发生在:

  1. 选择一个包含父实体的实体。
  2. 选择一个具有值对象的实体拥有一个命令

使用FindFirstFirstOrDefaultLastSingle和所有单个实体选择器命令时会出现此错误。

我测试了许多解决方案并检查生成的 sql 语句以找出一种非常独特的方法,而没有任何性能开销:

// This the way of getting one entity from oracle 12.1 without throwing Oracle exception => ORA-00918: column ambiguously defined without any extra overhead
var entities = await dbSet.Where(x => x.Id == id).Take(1).ToListAsync();
var entity = entities.FirstOrDefault();

另一个示例:

var entities = await dbSet.OrderByDescending(x => x.Id).Take(1).ToListAsync();
var entity = entities.FirstOrDefault();

IQueryable Linq 的末尾添加Take(1)并使用.ToList().ToListAsync()获取所有内容以执行语句并获取包含一条记录的列表。 然后使用 Enumerable Single Entity Selector 将列表更改为实体。

就这样。

暂无
暂无

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM