代码之家  ›  专栏  ›  技术社区  ›  ChrisHDog

无法保存实体框架继承的类型

  •  4
  • ChrisHDog  · 技术社区  · 18 年前

    我在我的数据模型中实现了一些每类型表继承(基本上有一个 BaseEntity 键入“我的项目”的所有基本信息和 Employer 从 基本实体 项目)。一切似乎都设置正确,当使用实体(通过ADO.net数据服务或通过Linq to实体)时,我可以看到 雇用者 类型和事情似乎是好的。当我创建一个新的 雇用者

    在上下文中,它似乎不是一个 .AddToEmployer 项目(仅限和) AddObject 或 AddToBaseEntity

    AddObject("Employer", NewEmployer) 我收到以下信息和错误消息:

    找不到EntitySet名称“DataEntities.Employer”。

    如果我使用 AddToBaseEntity(NewEmployer)

    我是否错过了建立遗产的一步?是否有某种特定的方法来保存继承的对象?我做错了什么?我认为基本问题是我应该有一个 AddToEmployer ,我需要做什么才能暴露出来?奇怪的是,这不是一个选项,因为我可以在客户端看到雇主类型,并可以执行以下操作:

    var NewEmployer = new Employer() -这似乎表明,我可以看到雇主类型的罚款。

    5 回复  |  直到 9 年前
        1
  •  7
  •   Robert Koritnik    16 年前

    我叫Phani,在ADO.NET数据服务团队工作。

    ResolveName 和 ResolveType

    它们可以帮助您解析客户端上的类型,在许多情况下都很有用,例如:

    1. 与服务器相比,客户端上的实体类型层次结构有所不同。
    2. 服务公开的实体类型参与继承,并且您希望在客户端上使用派生类型。

    解析名 用于在向服务器发出请求时更改连接上的实体的名称。

    在服务器上

    public class Employee {
        public int EmployeeID {get;set;}
        public string EmployeeName {get;set;}
    }
    
    public class Manager:Employee {
        public List<int> employeesWhoReportToMe {get;set;}
    }
    

    使用客户端处理Manager实体类型的实例时, 在将更改提交到服务器时,我们希望当实体参与继承时,负载中会出现类型信息。

    context.AddObject("Employees",ManagerInstance ); <-- add manager instance to the employees set.
    context.SaveChanges();
    

    这不是服务器上所期望的。

    context.ResolveName = delegate(Type entityType){
        //do what you have to do to resolve the type to the right type of the entity on the server
        return entityType.FullName;
    }
    

    类型解析器的使用方式与此相同。

    context.ResolveType = delegate(string entitySetName){
        //do what you have to do to convert the entitysetName to a type that the client understands
        return Type.GetType(entitySetName);
    }
    
        2
  •  2
  •   Luhmann    18 年前

    你只得到了一个实体集pr.基类,所以,AddToBaseEntity就是这样的解决方案。

    但听起来您的模型中有一个循环依赖项,因此实体框架无法确定保存顺序。

    检查派生实体上是否有baseentity的外键,并更新模型。

        3
  •  2
  •   ChrisHDog    18 年前

    我改变了一些事情,并且能够让它工作。我不太清楚基本问题是什么,但我想把我所做的作为参考。

    重建的表:我从ID/键列和单个数据列开始重建表。

    不幸的是,这会导致实体框架中的增强类不能有导航属性(所有导航属性都必须在基础实体上)的问题,因此继承将被证明不可用于我们的需要。

        4
  •  1
  •   Nenad Dobrilovic    18 年前

    您没有将雇主定义为实体集,就像实体类型一样。这就是在上下文对象中缺少AddToEntity的方式。一个类层次结构始终有一个实体集,在本例中,它是基类实体集。

    如果要获取实体集“雇主”,可以尝试手动编辑edmx文件并添加新的实体集“雇主”,然后将实体类型“雇主”设置为属于该实体集。这应该不难,我已经做过很多次了。

        5
  •  1
  •   JohnMetta    15 年前

    不确定早期版本,但EntityFramework4允许您将对象作为基本对象转储到上下文中,然后框架计算出服务器端引用。因此,您不会使用AddToInheritedObjects()(无论如何都不推荐使用),而是使用ObjectSet<>。Add()方法。

    下面是一个帮助器类示例:

    public ContextHelper
    {
            …
            _context = ModelEntities();
    
            public T Create<T>() where T : class
            {
                // Create a new context
                _context = new ModelEntities();
    
                // Create the object using the context (can create outside of context too, FYI)
                T obj = _context.CreateObject<T>();
    
                // Somewhat kludgy workaround for determining if the object is
                // inherited from the base object or not, and adding it to the context's
                // object list appropriately.    
                if (obj is BaseObject)
                {
                    _context.AddObject("BaseObjects", obj);
                }
                else
                {
                    ObjectSet<T> set = _context.CreateObjectSet<T>();
                    set.AddObject(obj);
                }
    
                return obj;
            }
            …
    }
    

    因此,假设您具备以下条件:

    class ObjectOne : BaseObject {}
    class ObjectTwo {}
    

    ContextHelper ch = ContextHelper()
    ObjectOne inherited = ch.Create<ObjectOne>();
    ObjectTwo toplevel = ch.Create<ObjectTwo>();
    …
    

    当然,记住ContextHelper应该有一个调用_context.SaveChanges()的公共Save()方法,或者应该有其他方法将对象更改推送到数据存储。

    这可能不是对任何关于继承的问题的直接回答,但希望能给人们一个回答具体问题的起点。