無法跟踪實體類型的實體框架實例

c# entity-framework-core

我有以下Entity Framework Core 1.1的實體和上下文:

public class Language {
  public String LanguageCode { get; set; }
  public virtual ICollection<LanguageI18N> LanguagesI18N { get; set; } = new List<LanguageI18N>();
}

public class LanguageI18N {
  public String LanguageCode { get; set; }
  public String TranslationCode { get; set; }
  public String Name { get; set; }        
  public virtual Language Language { get; set; }
}

public class Context : DbContext {

  public DbSet<Language> Languages { get; set; }
  public DbSet<LanguageI18N> LanguagesI18N { get; set; }

  public Context(DbContextOptions options) : base(options) { }

  protected override void OnModelCreating(ModelBuilder builder) {

    base.OnModelCreating(builder);

    builder.Entity<Language>(b => {
      b.ToTable("Languages");
      b.HasKey(x => x.LanguageCode);
      b.Property(x => x.LanguageCode).IsRequired(true).HasMaxLength(2).ValueGeneratedNever();        
    });

    builder.Entity<LanguageI18N>(b => {
      b.ToTable("LanguagesI18N");
      b.HasKey(x => new { x.LanguageCode, x.TranslationCode });      
      b.Property(x => x.LanguageCode).HasMaxLength(2).IsRequired(true);
      b.Property(x => x.TranslationCode).HasMaxLength(2).IsRequired(true);
      b.HasOne(x => x.Language).WithMany(x => x.LanguagesI18N).HasForeignKey(x => x.LanguageCode).IsRequired(true).OnDelete(DeleteBehavior.Restrict);
      b.HasOne(x => x.Language).WithMany(x => x.LanguagesI18N).HasForeignKey(x => x.TranslationCode).IsRequired(true).OnDelete(DeleteBehavior.Restrict);      
    });      

  }

}

然後我創建了一個語言,其翻譯名稱如下:

public class Program {

  public static void Main(String[] args) {

    DbContextOptionsBuilder builder = new DbContextOptionsBuilder<Context>();

    builder.UseInMemoryDatabase();

    using (Context context = new Context(builder.Options)) {

      Language language = new Language { LanguageCode = "en" };

      language.LanguagesI18N.Add(new LanguageI18N { LanguageCode = "en", TranslationCode = "en", Name = "English" });
      language.LanguagesI18N.Add(new LanguageI18N { LanguageCode = "en", TranslationCode = "pt", Name = "Inglês" });

      context.Languages.Add(language);

      context.SaveChanges();

    }         

  }

}

我正在使用代碼“en”創建一種語言,並使用英語和葡萄牙語翻譯其名稱。

當我運行代碼時,我收到以下錯誤:

未處理的異常:System.InvalidOperationException:無法跟踪實體類型“LanguageI18N”的實例,因為已經跟踪了具有相同鍵的此類型的另一個實例。添加新實體時,對於大多數鍵類型,如果未設置任何鍵,則將創建唯一的臨時鍵值(即,如果為鍵屬性指定了其類型的默認值)。如果要為新實體顯式設置鍵值,請確保它們不會與現有實體或為其他新實體生成的臨時值發生衝突。
附加現有實體時,請確保只有一個具有給定鍵值的實體實例附加到上下文。

我錯過了什麼?

UPDATE

該代碼適用於InMemoryDatabase以及Ivan Stoev建議的更改:

b.HasOne<Language>().WithMany().HasForeignKey(x => x.TranslationCode).IsRequired(true).OnDelete(DeleteBehavior.Restrict);

但是當我替換InMemoryDatabase時:

builder.UseInMemoryDatabase();

通過SQL Server數據庫:

  builder.UseSqlServer(yourConnectionString);

我收到以下錯誤:

Unhandled Exception: Microsoft.EntityFrameworkCore.DbUpdateException: 
An error occurred while updating the entries. See the inner exception for details. ---> System.Data.SqlClient.SqlException: 
The INSERT statement conflicted with the FOREIGN KEY constraint "FK_LanguagesI18N_Languages_TranslationCode". 
The conflict occurred in database "TestDb", table "dbo.Languages", column 'LanguageCode'.
The statement has been terminated.

知道為什麼嗎?

一般承認的答案

這裡

b.HasOne(x => x.Language).WithMany(x => x.LanguagesI18N).HasForeignKey(x => x.LanguageCode).IsRequired(true).OnDelete(DeleteBehavior.Restrict);
b.HasOne(x => x.Language).WithMany(x => x.LanguagesI18N).HasForeignKey(x => x.TranslationCode).IsRequired(true).OnDelete(DeleteBehavior.Restrict);      

您試圖將由Language - > LanguagesI18N導航屬性表示的同一個關聯映射到兩個不同的FK( LanguageCodeTranslationCode ),這是不可能的。第二行有效地覆蓋第一行,導致錯誤的設置。

由於您有兩個one-to-many關係,並假設第一行包含第一行的正確設置,第二行可以通過將最後一行更改為:

b.HasOne<Language>().WithMany().HasForeignKey(x => x.TranslationCode).IsRequired(true).OnDelete(DeleteBehavior.Restrict);

這種設置(兩側沒有導航屬性)在EF6中是不可能的,但由於HasOne / HasMany方法的無參數重載,EF Core完全支持。只需將它們(以及WithOne / WithMany )與模型導航屬性保持同步即可。



Related

許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow