2017-02-12 87 views
1

我有以下實體和語境實體框架核心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」創建一種語言,並以英文和葡萄牙語翻譯其名稱。

當我運行代碼,我得到了以下錯誤:

Unhandled Exception: System.InvalidOperationException: The instance of entity type 'LanguageI18N' cannot be tracked because another instance of this type with the same key is already being tracked. When adding new entities, for most key types a unique temporary key value will be created if no key is set (i.e. if the key property is assigned the default value for its type). If you are explicitly setting key values for new entities, ensure they do not collide with existing entities or temporary values generated for other new entities.
When attaching existing entities, ensure that only one entity instance with a given key value is attached to the context.

我缺少什麼?

UPDATE

的代碼與內存數據庫和伊萬Stoev建議的變化:

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

但是,當我更換內存數據庫:

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. 

任何想法,爲什麼?

+0

你是如何創建你的上下文對象的?它被注入了嗎?你如何將它添加到你的DI容器? – DavidG

+0

我只是在控制檯應用程序中使用連接字符串創建上下文,並且它運行良好,因爲我能夠獲得語言表的數量。 –

+0

所以你做'var context = new Context();'某處? (PS命名你的上下文類上下文很混亂!) – DavidG

回答

2

這裏

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導航屬性到兩個不同的FKS(LanguageCodeTranslationCode),這是不可能的。第二行有效覆蓋第一行,導致不正確的設置。

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

這樣的設置(W/O導航:

既然你有兩個one-to-many關係,並假設第一行包含第一個正確的設置,第二可以通過改變最後一行是設置雙方財產)在EF6中是不可能的,但在EF Core中得到了完美的支持,這要歸功於HasOne/HasMany方法的無參數過載。只要將它們(以及WithOne/WithMany)與您的模型導航屬性保持同步即可。

+0

你的建議只適用於InMemoryDatabase而不是真正的SQL數據庫......至少看起來這樣。我在我的問題中添加了更新,解釋了我嘗試的內容。 –

+0

實際上新的異常表明上述工作 - 創建了正確的FK約束。現在違反了你的插入,這意味着你已經指定了'Language'表中不存在的'TranslationCode',是嗎? –

+0

@IvanStoev就在這裏。語言代碼'pt'不會添加到語言表中,因此您無法添加專門用於所需關係的子代。 – Smit