4

我在我的数据模型中实现了一些每种类型的表继承(基本上有一个BaseEntity类型,包含我的项目的所有基本信息和从BaseEntity项目继承的Employer类型)。一切似乎设置正确,当使用实体(通过ADO.net数据服务或通过Linq实体),我可以看到Employer类型,似乎没有问题。当我创建一个新的Employer实体并尝试保存它时,问题就开始了。无法保存实体框架继承的类型

在似乎不是.AddToEmployer项目(仅限于和AddObjectAddToBaseEntity)的上下文中。

如果我使用AddObject("Employer", NewEmployer)我得到和错误消息:

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

如果我使用AddToBaseEntity(NewEmployer)我得到一个错误信息:

无法确定相关的操作有效的排序。由于外键约束可能存在依赖关系,所以模型需求会产生生成的值。

我错过了设置继承的步骤吗?有没有一些特定的方法来保存被继承的对象?我究竟做错了什么?我认为基本问题是我应该有一个AddToEmployer,我需要做些什么才能让它暴露出来?看起来很奇怪,因为我可以在客户端看到Employer类型,并且可以执行诸如以下操作,这似乎很奇怪:

var NewEmployer = new Employer() - 这似乎表明我可以看到Employer类型正常。

回答

2

我改变了一些东西,并能够得到这个工作。我不太确定基本问题是什么,但是想发布我所做的参考。

重建表格:我重建了只有ID/Key列和单个数据列的表格。

删除了额外的自动递增字段:我在BaseEntity和雇主上有一个自动递增的ID。我删除了Employer上的自动递增ID,并将Employer.BaseEntityID列和外键恢复为BaseEntity.BaseEntityID。 (这似乎是罪魁祸首,但我在这个被允许的印象之下)

不幸的是,这然后导致的问题,实体框架中enherited类不能有导航属性(所有的导航属性必须在基地实体),所以继承将证明对我们的需求是不可用的。

1

您没有将雇主定义为实体集,就像实体类型一样。这就是你在上下文对象中缺少AddToEntity的原因。总是为一个类层次结构设置一个实体,在这种情况下,它是BaseClass实体集。

如果您想获得实体集'Employer',您可以尝试手动编辑edmx文件并添加新的实体集'Employer',然后将实体类型'Employer'设置为属于该实体集。这不应该很难,我已经做了很多次。

我不确定是否有一些更常规的解决方案。

2

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

但它听起来像你在你的模型中有一个循环依赖,所以Entity框架不能找出保存的顺序。

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

7

我的名字是Phani,我在ADO.NET数据服务团队工作。

ResolveNameResolveType方法将帮助您自定义客户端在发送到服务器的负载中写入的类型信息以及服务器的响应负载如何实现。

他们帮助您解决在客户端类型和在许多情况下是有用的,一对夫妇的例子是:

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

ResolveName用于更改我们在向服务器发出请求时放置在网络上的实体的名称。

考虑这个数据模型: 在服务器

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

即将在两年后,但在保持其相关的搜索流量的利益,这里有一个方法,我很快在一个方便的类工作围绕这一点,我们使用快速填充我们与分期资料数据库。

不确定早期版本,但Entity Framework 4允许您将对象作为基础对象转储到上下文中,然后框架计算出服务器端引用。因此,您不会使用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应该有一个公共的Save()方法,它调用_context.SaveChanges() - o您应该有其他方法将对象更改为数据存储。

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

+0

作为一个说明,我忘了提及 - 实现IDisposable使这真的很好。 – JohnMetta 2010-12-23 20:16:39