转换一个EF codeFirst基类继承的一个类(使用表每型) [英] Converting a EF CodeFirst Base class to a Inherited class (using table-per-type)
问题描述
我使用的EF $ C C一$,并定义了两个类,如下所示:
I am using EF Code First and have two classes defined as follows:
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<Building>();
}
public virtual IList<Building> Favourites { get; set; }
}
本使用表,每个类型的继承,并定义了DB模式如下:
This uses Table-Per-Type inheritance and defines the DB schema as follows:
Users Table
Id int PK
Username nvarchar(max)
Email nvarchar(max)
Visitors Table
Id int PK (FK to Users table)
这是到底我希望它来构建它。 现在的问题是,如果我创建一个User对象,然后将其保存到数据库,如何将我以后能延伸到一个访问者(如果我需要?)我需要将其删除用户创建一个新的访客或可我一些如何铸就用户到访问者的对象,并在用户表中的条目将保持不变,新的条目将被添加到访客表引用用户?像下面的code?
This is exactly how I wanted it to structure it. Now my question is, if I create a User object and save it to the DB, how will I later on be able to extend that into a Visitor (if I need to?) Will I need to delete the user and create a new Visitor or can I some how cast the user into a visitor object and the entry in the user table will remain intact and a new entry will be added to the visitor table referencing the user? Something like the below code?
Context.Set<User>().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<Visitor>().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<Visitor>().Where(v=>v.Id == 1).FirstOrDefault();
if (visitor==null)
{
visitor = new Visitor(Context.Set<User>().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();
我想在上面code中的第二种方法可以工作,如果我不仅可以正确地附加到上下文。无论如何,code以上只是为了告诉你什么是我想要的目的。我知道这是行不通的。任何人都可以提出一个更高贵的办法?
I think the second approach in the above code may work if I can only attach it to the context correctly. Anyway, the code above is only to show you what I am trying to achieve. I know it will not work. Can anyone suggest a more elegent approach?
感谢您
推荐答案
您是的几乎的存在......最关键的是为分离现有实体的那么的附加新的。
You were almost there... The key is to detach the existing entity, then attach the new one.
下面是一个例子:
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<Animal> 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));
}
}
这篇关于转换一个EF codeFirst基类继承的一个类(使用表每型)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!