0

我在 EF 模型中定义了一个简单的 2 对象继承,Person <- User。

Person 是基础实体/类,它不是抽象的,它包含名字、姓氏、电子邮件等字段。

User 是派生的实体/类,包含用户名、lastlogin、islockedout 等字段。

数据库使用每个类型的表模式,因此有一个表用于人员,另一个表用于用户。两者都使用相同的主键字段 PersonID。PersonID 是一个 IDENTITY 列,但在 EDM 中,PersonID 的 StoreGeneratedPattern 设置为 None。

因为这是一个 table-per-type 继承模式,所以可能有一个 Person 行/对象没有对应的 User 行/对象。这样系统就可以包含关于非用户的数据。但是,一个人最终可能会成为用户,这就是我遇到问题的地方。

我有一个针对这种情况的测试用例,其中系统找到了一个想要变成用户的人。我尝试在新的用户对象上设置 PersonID 字段,将其添加到 ObjectContext 并保存更改。发生的情况是数据库创建了一个新的 Person 行以及新的 User 行,而忽略了我为 PersonID 设置的值。

我怎样才能解决这个问题?我是否必须创建存储过程来处理 EDM crud 操作?

4

2 回答 2

2

这是你的问题:

我有一个针对这种情况的测试用例,其中系统找到了一个想要变成用户的人

在 C# 或我所知道的任何其他基于类的 OOPL 中,对象不能更改类型。EF 不会改变这一点。

你需要改变你的设计。这不是OO。我去年写过这个:

在设计一个好的对象关系映射时,你必须克服的心理障碍之一是倾向于主要用面向对象的术语或关系术语来思考,这取决于你的个性。然而,一个好的对象关系映射同时包含一个好的对象模型和一个好的关系模型。例如,假设您有一个数据库,其中包含一个人员表,以及员工和客户的相关表。一个人可能在所有三个表中都有记录。现在,从严格关系的角度来看,您可以为员工构建一个数据库 VIEW,为客户构建另一个数据库,这两个数据库都包含来自 People 表的信息。使用一个视图或另一个视图时,您可以暂时将个人视为“只是”一个员工或“只是”一个客户,即使你知道他们都是。因此,来自这种世界观的人可能会尝试进行 OO 映射,其中 Employee 和 Customer 都是 Person 的(直接)子类。但这不适用于我们拥有的数据;由于一个人同时拥有员工和客户记录(并且由于没有任何 Person 实例可以同时属于具体子类型 Employee 和 Customer),因此 Person 和 Employee 之间的 OO 关系需要是组合而不是继承,对于 Person 和 Customer 也是如此。

于 2010-09-24T16:40:38.513 回答
0

我能够解决这个问题,尽管我对这个解决方案并不完全满意。我最终编写了存储过程来映射 Person 和 User 的插入、更新和删除操作(因为它们在同一个实体集中,都必须映射到所有 3 个存储过程)。User 的插入存储过程接受一个 PersonID 参数,并使用它来决定是创建一个新的 Person 行,还是附加到现有的 Person 行。

问题是必须将 PersonID 映射为 sproc 输入参数和结果列绑定。当 db 必须生成新的 PersonID 时,我们必须使用结果绑定将其取回,以便其他表获取引用 PersonID 的外键列的正确值。除了......您不能同时将 User.PersonID 映射为输入参数和结果列绑定。这会导致运行时异常“无法确定依赖操作的有效排序。由于外键约束、模型要求或存储生成的值,可能存在依赖关系。”

我最终向 User 表(以及相应的概念模型)添加了一个新列,它是一个可为空的 int(我称之为 BasePK)。在 EDM 中,我将此属性的 getter 和 setter 设置为受保护的,以将它们隐藏在公共界面中。然后,我将 BasePK 映射为 sproc 输入参数,并将 PersonID 映射为结果列绑定,以便在生成标识值时接收标识值。User 构造函数的一个重载如下所示:

公共用户(int personID):base(){ this.BasePK = personID; }

所以现在,每当我想将现有的 Person 转换为 User 时,我只需要使用这个重载来构造用户。

int personID = [某种搜索人员并返回他/她的 PersonID 的方法]; var User = new User(personID);

当 ObjectContext 插入实体时,它通过 BasePK 属性将 PersonID 传递给存储过程。存储过程完成后,它将 PersonID 返回给实际的主键属性。

我不喜欢必须添加列和属性来完成此操作的想法,但它确实与我对 Craig 的回答的评论相吻合:我希望能够插入具有新专业的 Person 而无需更改/重组 Person每次实体。这样,至少我可以保留派生实体类型中的所有更改,即使这意味着这些更改涉及添加在物理存储中始终为空的无意义列。

于 2010-09-25T14:40:18.350 回答