将EF CodeFirst Base类转换为Inherited类(使用table-per-type)

我正在使用EF Code First,并且有两个类定义如下:

public class User { public int Id { get; set; } public string Username { get; set; } public string Email { get; set; } } [Table("Visitors")] public class Visitor : User { public Visitor() { Favourites = new List(); } public virtual IList Favourites { get; set; } } 

这使用Table-Per-Typeinheritance并定义DB模式,如下所示:

 Users Table Id int PK Username nvarchar(max) Email nvarchar(max) Visitors Table Id int PK (FK to Users table) 

这正是我想要它构建它的方式。 现在我的问题是 ,如果我创建一个User对象并将其保存到数据库,我将如何将其扩展到一个访问者(如果我需要?)我是否需要删除用户并创建一个新的访问者或者我可以将一些用户转换为访问者对象,并且用户表中的条目将保持不变,并且新条目将添加到引用用户的访问者表中? 像下面的代码?

 Context.Set().Add(new User(){Id=1, Username="Bob", Email="bob@mail.bob"}); Context.SaveChanges(); //and elsewhere in the project I want to do this sort of thing: Context.Set().Where(v=>v.Id == 1).FirstOrDefault().Favourites.Add(someFavouriteBuilding); //This obviously doesn't work, because the FirstOrDefault call returns null, so it will throw an exception Context.SaveChanges(); //or maybe this can be modified slightly to work?: var visitor = Context.Set().Where(v=>v.Id == 1).FirstOrDefault(); if (visitor==null) { visitor = new Visitor(Context.Set().Where(u=>u.Id == 1).FirstOrDefault()); // this contructor copies all the property values accross and returns a new object } visitor.Favourites.Add(someFavouriteBuilding); //This obviously doesn't work either var entry = Context.Entry(visitor); entry.State = EntityState.Modified;//here it throws this error: An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key. Context.SaveChanges(); 

我认为如果我只能正确地将它附加到上下文中,上面代码中的第二种方法可能会起作用。 无论如何,上面的代码只是为了向您展示我想要实现的目标。 我知道它不会起作用。 任何人都可以提出更加优雅的方法吗?

谢谢

几乎就在那里……关键是分离现有实体, 然后附上新实体。

这是一个例子:

 using System.Data; using System.Data.Entity; using System.Diagnostics; public class Animal { public long Id { get; set; } } public class Dog : Animal { } public class AnimalsContext : DbContext { public DbSet Animals { get; set; } } public class Tester { public void Test() { var context = new AnimalsContext(); var genericAnimal = new Animal(); context.Animals.Add(genericAnimal); context.SaveChanges(); // Make a new clean entity, but copy the ID (important!) var dog = new Dog { Id = genericAnimal.Id, }; // Do the old switch-a-roo -- detach the existing one and attach the new one // NOTE: the order is important! Detach existing FIRST, then attach the new one context.Entry(genericAnimal).State = EntityState.Detached; context.Entry(dog).State = EntityState.Modified; context.SaveChanges(); var thisShouldBeADog = context.Animals.Find(genericAnimal.Id); // thisShouldBeADog is indeed a Dog! Debug.Assert(thisShouldBeADog is Dog); // And, of course, all the IDs match because it's the same entity Debug.Assert((genericAnimal.Id == dog.Id) && (dog.Id == thisShouldBeADog.Id)); } } 

接受的答案对我不起作用。 通过每个数据库使用多个上下文,或者因为EF6以某种方式忽略了这一点。

只有我能解决的解决方案是我在这个答案中描述的解决方案: https : //stackoverflow.com/a/28380804/2424989

我会创建一个新记录并删除旧记录。 我认为您不应该有效地更改现有对象的类,也不要删除和创建尝试重用数据库密钥的记录。

数据库主键应该没有意义。 如果您需要为记录分配有意义的ID,请为其添加新字段。 想想你的堆栈溢出ID,我敢打赌,这不是他们数据库中的主键。