簡體   English   中英

具有可選鏈接實體的實體框架核心代碼優先外鍵

[英]Entity Framework Core code-first foreign key with optional linked entity

我有一個文件表,我想在其他 2 個表中引用它。 每個文件都是其中一個表獨有的,這意味着我的外鍵在至少一個鏈接表中沒有實體,某些文件可能有一個填充鍵,它根本沒有鏈接到任何實體(因為它將是稍后裝箱)。

關系:(1 -> n)

Item <- File -> Image

這會導致 insert/ SaveChanges上的外鍵異常,因為數據庫無法找到鏈接的實體。

我搜索了一個解決方案,但找不到任何解決此問題的文章,而且我提出的解決方案至少有一個代碼異味。

問題:如何鏈接這 3 個表而不會出現數據庫異常並產生代碼/數據庫氣味?

還是整個數據架構有問題,我應該嘗試一些不同的東西(如果有的話)?

我想出但不想使用的解決方案:

  • 沒有外鍵,但有一個新查詢
  • 使用只有鏈接實體的實體的中間表(文件->鏈接->項目)
  • Files表拆分為ItemFilesImageFiles (我聽說這是 DB 的味道)

其他信息:

  • .NET 核心 3.1
  • EF Core:最新
  • 數據庫:Sqlite

縮短型號:

public class FileData
{
    public Item Item { get; set; }
    public ImageData Image { get; set; }
    public Guid Id { get; set; }
    public string HashKey { get; set; }
    // ...
}

public class Item
{
    public FileData[] Files { get; set; }

    public Guid Id { get; set; }
    public string HashKey { get; set; }
    // ...
}

public class ImageData
{
    public FileData[] Files { get; set; }
    public Guid Id { get; set; }
    public string HashKey { get; set; }
    // ...
}

數據庫配置:

public class FileDataConfiguration : IEntityTypeConfiguration<FileData>
{
    public void Configure(EntityTypeBuilder<FileData> builder)
    {
        builder.HasKey(file => file.Id);
        builder.HasIndex(file => file.HashKey);
        // ...
    }
}

public class ItemConfiguration : IEntityTypeConfiguration<Item>
{
    public void Configure(EntityTypeBuilder<Item> builder)
    {
        builder.HasKey(item => item.Id);
        builder.HasMany(item => item.Files)
            .WithOne(file => file.Item)
            .IsRequired(false)
            .HasForeignKey(file => file.HashKey)
            .IsRequired(false)
            .HasPrincipalKey(item => item.HashKey);
        builder.HasIndex(file => file.HashKey);
        // ...
    }
}

public class ImageDataConfiguration : IEntityTypeConfiguration<ImageData>
{
    public void Configure(EntityTypeBuilder<ImageData> builder)
    {
        builder.HasKey(image => image.Id);
        builder.HasMany(image => image.Files)
            .WithOne(file => file.Image)
            .IsRequired(false)
            .HasForeignKey(file => file.HashKey)
            .IsRequired(false)
            .HasPrincipalKey(image => image.HashKey);
        builder.HasIndex(image => image.HashKey);
        // ...
    }
}

此代碼引發異常

// both examples throw an exception, independent of each other
//example 1:
dbContext.Files.Add(
    new File(){
        HashKey="1"
    }
);
dbContext.SaveChanges();

//example 2:
dbContext.Files.Add(
    new File(){
        HashKey="2"
    }
);
dbContext.Items.Add(
    new Item(){
        HashKey="2"
    }
);
dbContext.SaveChanges();

通常,您的FileData實體應包含ItemImageData實體的Guid外鍵,而不僅僅是導航屬性,即Guid ItemIdGuid ImageId 例如:

public class FileData
{
    public Guid ItemId { get; set;}
    public Item Item { get; set; }
    public Guid ImageId {get; set; }
    public ImageData Image { get; set; }
    public Guid Id { get; set; }
    public string HashKey { get; set; }
    // ...
 }

同樣在 Fluent Api 中同時配置ItemImageData時,此配置應該足夠了

 builder.HasMany(item => item.Files)
        .WithOne(file => file.Item)
        .OnDelete(DeleteBehavior.NoAction);

最后我決定放棄外鍵,因為我不需要更新其他實體並手動啟動文件查詢。 似乎不可能將文件添加為屬性,因為錯誤一直被拋出(我嘗試了這個解決方案)

使用的約束列表:Item.Id => Key Item.Hash => Indexed, Unique

Image.Id => 關鍵 Image.Hash => 索引,唯一

File.Id => 密鑰 File.Hash => 索引,不唯一

我決定保留 Item 和 Image 的 ID 的原因之一是其他實體主要通過 ID 引用這些,而不是 hash 和 hash 可能會更改,需要大量更新。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM