簡體   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