使用对象 ID 与将对象填充到其他类之间的权衡是啥? [关闭]

Posted

技术标签:

【中文标题】使用对象 ID 与将对象填充到其他类之间的权衡是啥? [关闭]【英文标题】:What are the tradeoffs between using object ID's vs stuffing the objects into other classes? [closed]使用对象 ID 与将对象填充到其他类之间的权衡是什么? [关闭] 【发布时间】:2014-02-21 02:36:57 【问题描述】:

编辑:早期的出色回应让我意识到,我提出的关于权衡的问题结合@Leo 的变体会更有用。

我正在使用 Code-First EF 开发数据模型,但对可能非常基本的内容感到不专业。

给定Team和Player类,一个Team有N个Players,可以设计数据模型

1) 将 Players 作为成员子对象:

class Team

    int Id;
    ICollection<Player> Players;

或 2)(被拒绝为没有真正的好处)我们可以将参考ID传递给玩家

class Team

    int Id;
    ICollection<int> PlayerIds;

或 3) 使用外键 ID 实现模型独立

class Team

    int Id;


class Player

    int Id;
    int TeamId;

我可以看到第 3 种方法的一些明显好处,如下面的@Leo 所示。因此,在这一点上,也许我的问题最好表述为“在什么情况下可能更喜欢使用变体 1”?

【问题讨论】:

您是从数据库的角度还是从代码的角度询问?我不知道为什么我想要一个 ID 集合以便我可以查找关联的对象,因为这很快就会成为数据库的重新实现。 可能没什么大不了的,但是您会浪费内存来存储所有值类型以及这些 ID 分别引用的所有引用类型。此外,您的 C# 代码的可读性和臃肿程度会大大降低,因为还需要通过 team 类中的 id 从某个单独的玩家列表中获取实际的玩家。这与 oop 的想法背道而驰。 【参考方案1】:

好吧,我想你是对的,你不会找到很多资源来概述你应该如何设计你的数据层和/或模型。实际上,您将找到的资源很可能会描述不同的方法,并且可能会建议您应该(或不应该)做什么。但是,我发现该主题非常主观,您永远不应该将其与上下文隔离开来,我的意思是,只有您应该知道哪种方法最适合您的情况,因为您是最了解您的系统的人内在因素。这两种方法对我来说都很好,你应该始终做的是努力保持子系统之间的松散耦合。基本上,这个映射...

class Team

    int Id;
    ICollection<Player> Players;

使团队依赖于玩家,如果(并且仅当)这是一个永远不应该改变的要求,这很好。此外,如果玩家将始终属于一个且仅属于一个团队,那么您可以采取另一种方法,即保持您的团队模型/实体不依赖...

class Team

    int Id;
    string TeamName;


class Player

    int Id;
    int TeamId;

数据库查询在这里不应该是一个问题,您的表示层和模型层应该尝试从关系中抽象出来,如果您不能......比如说,您需要展示/展示一个团队及其球员,那么您将最- 可能需要 2 个数据库查询(如果您不想使用连接和清理重复的字段...团队,在这种情况下),我认为进行 2 个单独的数据库查询没有任何问题。

编辑

我猜方法 1 使耦合更加紧密,您应该始终避免它,想象一下,如果您有机会需要 Player 类的名称,您必须在整个系统中进行大量更改。此外,如果您要公开 API,对您的客户来说可能会更糟。但是,正如我所说,这完全取决于您系统的核心要求……如果这些是核心(难以更改)要求,那么您不必担心。

“在什么情况下可能更喜欢使用变体 1”?

再一次,这都是关于需求的,如果您的需求表明团队和玩家之间存在关系,那么只要您可以在两个实体之间建立关系,所有方法都可以。

【讨论】:

你知道,看着你的回答,我意识到你的第二个例子,其中 Team 独立于 Player 类,是我在我自己的第二个例子中真正想要表达的。我的问题可以更好地表述为“哪些因素使您通过使用外键 ID 倾向于模型独立性,以及哪些因素会使您倾向于两个类的紧密耦合” 外键表示一种关系,而关系表示一种依赖关系,其中孩子依赖于其父母,但父母不依赖于其孩子。如果您确定存在关系是因为要求如此。接下来您需要确定这些各方之间的关系。关系的性质将决定何时需要松散耦合,何时不需要。我希望你明白,在建立关系时有时需要耦合 @Leo 在另一个类中拥有一个类的 ID 与关联相同吗?还是仅当类型本身用作其他类中的属性时?【参考方案2】:

在我看来答案是:两者都不是。

在实体框架中,您可以在两种类型的关联中进行选择

独立关联,其中您只有对另一个对象的引用。一个例子是

class Player

    int Id;
    Team Team;

外键关联,其中您有一个引用一个原始外键值:

class Player

    int Id;
    [ForeignKey("Team")]
    int TeamId;
    Team Team;

您的替代方案 2) 不是一个选项,因为您无法在数据库字段中存储整数列表。此外,您需要 Ids 做什么?没有玩家,它们毫无意义。

来自 DDD 背景的人总是不赞成外键关联,因为域模型不应该有任何存储实现的概念。尽管如此,当您使用 EF 时,它仍然是推荐的方法。原因如下:

当您想要存储新播放器时,您可以设置TeamTeamId 属性。现在,如果您碰巧有Team,这并不重要。但是,在许多情况下,您只会拥有 TeamId(例如,因为它是从下拉列表中选择的)。对于独立关联,您必须首先进行数据库往返以获取Team,然后设置属性。只需设置Id 更简单,性能更好。

如果您只存储TeamId,实际上您没有关联,因此不能将其列为关联的第三种选择。这不是一个可行的选择。您总是需要以某种方式加入才能获得关联的Team。但是,如果您想一次性存储一个新的Team 和一个新的Player 怎么办?您必须首先存储Team,获取其分配的Id,设置PlayerTeamId 并存储Player,所有这些都包含在TransactionScope 中。使用 FK 关联,您只需创建对象,设置 player.Team = team,EF 会计算出插入对象的顺序并为您设置 FK 值。

所以我想说的是,在优化用作实体框架概念模型的类模型时,松散耦合、关注点分离等 DDD 原则充其量在后台发挥作用。这个类模型不是领域模型,它是一个数据层first and foremost。

【讨论】:

【参考方案3】:

我认为减少耦合的代价是增加复杂性。事实上,我怀疑您在整个应用程序中维护或增加了耦合量,因为您只是将获取和操作这些对象的责任转移到中间类 - 或者更糟糕的是,您开始将数据访问逻辑合并到您的模型。

【讨论】:

【参考方案4】:

除非Id 与您的概念模型相关,否则我不会将其包含在模型中。它似乎是数据库实现的一个细节,而不是模型的真正部分。

一支球队有球员。它没有玩家 ID。

您还应该考虑团队Id 是否与您的模型相关。如果您正在模拟一场(美式)足球比赛,那么球员球衣上的号码可能很重要。但是您不会显示玩家的员工 ID。

【讨论】:

以上是关于使用对象 ID 与将对象填充到其他类之间的权衡是啥? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

历史推送和替换之间的权衡是啥?

java中可以将父类对象强制转换为子类对象吗?直接将父类对象强制转换为子类对象,与将上转型对象强制

OOP:将对象与将属性传递给方法

单例对象和基类对象之间的区别是啥[重复]

实体框架 6:将子对象添加到父列表与将子对象的导航属性设置为父对象

对象数组与对象对象