简体   繁体   English

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

[英]Converting a EF CodeFirst Base class to a Inherited class (using table-per-type)

I am using EF Code First and have two classes defined as follows: 我正在使用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<Building>();
    }
    public virtual IList<Building> Favourites { get; set; }
}

This uses Table-Per-Type inheritance and defines the DB schema as follows: 这使用Table-Per-Type继承并定义DB模式,如下所示:

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

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? 现在我的问题是 ,如果我创建一个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();

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? 任何人都可以提出更加优雅的方法吗?

Thank you 谢谢

You were almost there... The key is to detach the existing entity, then attach the new one. 几乎就在那里......关键是分离现有实体, 然后附上新实体。

Here's an example: 这是一个例子:

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));
    }
}

Accepted answer didn't work for me. 接受的答案对我不起作用。 Either by using multiple contexts per database, or because EF6 somehow ignores this. 通过每个数据库使用多个上下文,或者因为EF6以某种方式忽略了这一点。

Only solution that worked for me is the one I described in this answer: https://stackoverflow.com/a/28380804/2424989 只有我能解决的解决方案是我在这个答案中描述的解决方案: https//stackoverflow.com/a/28380804/2424989

I would create a new record and delete the old record. 我会创建一个新记录并删除旧记录。 I don't think you should effectively change the class of an existing object, nor delete and create records attempting to reuse the database key. 我认为您不应该有效地更改现有对象的类,也不要删除和创建尝试重用数据库密钥的记录。

Database primary keys should be meaningless. 数据库主键应该没有意义。 If you need to assign a meaningful ID to your records then add a new field for that. 如果您需要为记录分配有意义的ID,请为其添加新字段。 Think of your stack overflow ID, I bet that's not the primary key in their database. 想想你的堆栈溢出ID,我敢打赌,这不是他们数据库中的主键。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 实体框架每个类型的表:1:0…*与派生类的FK关系-是基类还是派生类的FK? - Entity Framework table-per-type: 1:0…* FK relationship with a derived class - is FK of base class or derived class? EF Codefirst将基类转换为派生类 - EF Codefirst Convert Base Class to Derived Class 无法将MVC脚手架存储库与继承的类(每个类型的表)一起使用 - Using MVC scaffolding repository with inherited classes (table-per-type) isn't working EF 5中的CodeFirst中每个表映射的类型 - Type Per Table Mapping in CodeFirst in EF 5 EF Table-Per-Type:将新的子代添加到现有父代 - EF Table-Per-Type: Add new child to an existing parent 在使用带有实体框架的Table-per-Type时,如何仅获取基表行? - How do I get just the base table rows when using Table-per-Type with Entity Framework? 使用 ef core 使用 Table-per-Type (TPT) 方法创建子类型的子类型 - Creating subtype of a subtype with Table-per-Type (TPT) approach using ef core EF Core实现了Table-Per-Concrete-Type,具有抽象基类的流畅映射 - EF Core implementing Table-Per-Concrete-Type with fluent mapping of abstract base class 每种类型的表代码优先-如何区分基本类型是子类型 - Table-per-Type Code First - How to differentiate if Base type is sub type 每个类型的表继承插入问题 - Table-per-type inheritance insert problem
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM