单个实体的所有者和实体组的所有者。约束还是关系?

时间:2019-02-07 11:56:28

标签: database entity-framework database-design domain-driven-design relationship

简单的模型。三个简单的主要实体:任务所有者 TasksGroup

  • 许多所有者可能有许多任务,并且相反(多对多)。
  • 任务可以选择仅属于一个 TasksGroup ,但是 TasksGroup 可能包含许多 Tasks (一对一-很多)

现在是我最棘手的部分。 TasksGroup 中每个 Task 所有者必须相同。还可以更改 TasksGroup 中的所有 Tasks Owners ,如果没有,可以更改单个 Task Owners 。不属于任何 TasksGroup

应该有检查约束吗?还是在 TasksGroup 所有者之间建立了“主”关系?如果任务属于组,那么任务所有者之间的关系如何?设计这个的好方法是什么?

4 个答案:

答案 0 :(得分:1)

这种模型中的常见策略是通过要求每个任务都属于一个任务组来简化它。这样一来,您就可以删除任务与所有者之间的直接关系,而以将单个任务TaskGroups用作独立任务为代价。

答案 1 :(得分:1)

  

TasksGroup中每个任务的所有者必须相同

可以通过首先在TaskOwnerTaskOwner之间定义一个结点类/表来完成数据库约束,这在多对多关系中是标准的。

如果必须将TaskGroup限制在一个所有者的任务上,则将其连接到的自然位置是任务和所有者信息可用的地方,即联结表。但是,仅用一个FK(例如GroupId)来完成操作是不够的。 TaskGroup本身必须限制为一个所有者。它需要一个OwnerId作为其PK的一部分,因此TaskOwner可以由OwnerIdGroupId引用。最后,TaskGroup的{​​{1}}必须是OwnerId的FK,以确保OwnerTaskOwner指向同一所有者。相当于这个数据库模型:

enter image description here

  

也有可能更改TasksGroup中所有任务的所有者

通常,严格的约束和灵活性是相互排斥的。 TaskGroup引用的这一环很难破解。 OwnerId中的OwnerId必须更改,但这需要四个步骤:

  • TaskOwner设置为GroupId
  • 更改null
  • 更改OwnerId的{​​{1}}
  • 还原TaskGroup

使用SQL足够复杂,但是使用Entity Framework更加困难,因为EF不允许修改主键属性。使用EF,您必须删除OwnerId,创建新的,然后设置TaksOwner.GroupIdTaskOwner。并非没有,但一切都是灵活的!

答案 2 :(得分:0)

我会在RequiredOwners上使用TaskGroup种。实际上,一个人甚至可能具有不同类型的TaskGroup实例,其中一种类型要求分配的任务具有相应的所有者,而其他人则可能具有不同的规则。但是,这取决于域,因此如果您所指的是真实域,您将知道:)

但这实际上是最简单的实现,方法是让任务组拥有所有者列表。好吧,TaskGroup将包含ID或代表所有者的值对象的列表。配置任务所有者后,甚至可以从任务组开始管理任务的所有者分配。

答案 3 :(得分:0)

如果您的DBMS支持这些模式,那么您可以使用简单的模式加上常规的数据库约束来执行此操作(并且可以忍受所产生的性能)。不幸的是,大多数人没有。

除此之外,最干净的方法是重叠外键(超级)。这是一种不需要NULL的伪代码关系方法。数据类型和无关的属性被省略:

create table Task {
  TaskId,
  key { TaskId }
};

create table Owner {
  OwnerId,
  key { OwnerId }
};

create table TaskOwner { /* Bog standard association table */
  TaskId,
  OwnerId,
  key { Taskid, OwnerId }
  reference TO_T { TaskId } references Task { TaskId },
  reference TO_O { OwnerId } references Owner { OwnerId }
};

create table TaskGroup {
  GroupId,
  OwnerId,
  key { GroupId }, /* Each group has exactly one owner */
  reference TG_O { OwnerId } references Owner { OwnerId }
};

create table TaskGroupTask {
  TaskId,
  GroupId,
  OwnerId,
  key { TaskId }, /* Each task may belong to at most one group */
  reference TGT_TO { TaskId, OwnerId } references TaskOwner { TaskId, OwnerId },
  /* Foreign superkey coming up */
  reference TGT_TG { GroupId, OwnerId } references TaskGroup { Group, OwnerId }
};

线索是,TaskGroupTask.Ownerid作为对TaskOwnerTaskGroup的引用的一部分,承担着双重责任,从而确保组的所有者与每个组的所有者相同任务。这里有一个外来超键-TGT_TG是指TaskGroup键的超集-但是,如果您的DBMS反对,则可能的解决方法是在超集上创建一个(多余的)唯一索引。

乍一看,拥有一个单独的TaskGroupTask表而不是可为空的TaskOwner.GroupId属性似乎有点过头,但是它允许您使用简单的键约束来强制执行任务可能属于的规则最多一组。另外,它避免了NULL。

{ GroupId } -> { OwnerId }中有一个功能依赖项TaskGroupTask,它违反了Boyce-Codd规范形式,但是冗余性受TGT_TG引用控制,因此有必要执行以下规则:情况。

更改组的所有者(及其所有任务)需要在同一语句/事务中更新三个表,但是适当的RDBMS对此应该没有问题。

此设计确实允许一个任务属于多个所有者,并且处于同一组中,从而造成一种情况:一个组中的所有任务都属于同一所有者,但它们属于其他所有者(尽管不是组)。从您的问题尚不清楚这是否是一个问题,因此请让我知道。该设计还禁止没有所有者的团体,但我认为这是可以的。