【问题标题】:Model Relationships: efficiency in defining the relationship within the model模型关系:定义模型内关系的效率
【发布时间】:2017-09-29 18:31:21
【问题描述】:

我想,这是一个高层次的问题,更多的是学者而不是挖沟者。

问题一:

在定义与另一个模型的外部关系时,例如一对多关系,通常以以下方式定义:

public virtual ICollection<OtherModel> OtherModel { get; set; }

但是,我也看到它以下列方式定义:

private ICollection<OtherModel> _otherModel;
public virtual ICollection<OtherModel> OtherModel {
  get { return _otherModel ?? ( _otherModel = new List<OtherModel>() ); }
  set { _otherModel = value }
}

这对我来说确实有意义:如果没有从 OtherModel 引用此模型的条目(空值),则 null-coalescing 运算符确保创建了一个空白的、空的 OtherModel 集合。据我所知,这是一项安全措施。

然而,上述的演变似乎是这样的:

public class ThisModel {
  // Assorted model items

  public virtual ICollection<OtherModel> OtherModel { get; set; }

  public ThisModel(){
    OtherModel = new List<OtherModel>();
  }
}

不幸的是,我没有看到两者如何等效。当OtherModel 没有引用ThisModel 中的任何内容时,上面的第二个代码块显然使用了空合并运算符来调用空白列表ONLY;当结果列表无论如何都会为空时。

当我阅读第三个代码块时,我将其解释为 OtherModel 的列表,每次都会调用 ThisModel

我希望有人可以对两者之间的任何差异进行一些澄清。

问题 2:

另一方面,我们要求在 OtherModel 中输入条目。通常我们在OtherModel中建立反向关系是这样的:

public virtual ThisModel ThisModel { get; set; }

但是我也看到它以下列方式定义:

public class OtherModel {
  // Various model stuff

  private ThisModel _thisModel;
  public virtual ThisModel ThisModel {
    get { return _thisModel; }
    set {
      if (value == null) throw new ArgumentNullException(nameof(value));
      _thisModel= value;
      ThisModelId = value.ThisModelId;
    }
  }
}

关键是,因为OtherModel 有一个必需的外键,如果该外键最终被强制输入一个空条目,if 语句显式抛出一个空异常。我喜欢这个。它确保对于所需的外键,不能使用或不能引入空值。它确保在 CRUD 操作中的任何内容到达数据库之前很久就完成任何此类拒绝,并充当备份,以防业务逻辑(在堆栈中更高,使用视图模型)意外地没有扩展以涵盖该问题。

在这种情况下,我的问题是如何将其浓缩成更有效的东西。

【问题讨论】:

    标签: c# asp.net asp.net-mvc model asp.net-mvc-5


    【解决方案1】:

    你是对的。它们是不同的,构造函数版本实际上是一种反模式。在构造函数中,您正在初始化一个空列表,无论该列表是否有值。例如,如果 EF 要初始化一个列表确实有值的实例,则首先将该值设置为一个空列表,然后将其再次设置为它应该由 EF 包含的列表。诚然,简单地创建一个空列表并不是效率低下,但您仍然会消耗一些 RAM 和 CPU 来执行最终不必要的操作。

    自定义的getter和setter版本是lazy-set的,所以空列表只有在值为null时才会初始化,这意味着不会浪费资源。再说一次,这不是一个巨大的交易,但是像这样的大量低效率最终会导致真正的问题(比如千刀万剐)。

    不过,只是增加了一个问题:在 C# 6.0 中,您实际上可以在不使用自定义 getter 和 setter 的情况下提供默认值。所以下面真的是最优化的方式:

    public virtual ICollection<OtherModel> OtherModel { get; set; } = new List<OtherModel>();
    

    它的工作方式与自定义 getter/setter 版本完全相同,只是没有繁琐。

    【讨论】:

    • 哇,谢谢!我一直在研究 C# 6 的特性,但还没有明确地运行过这个示例。
    • C# 7 和 7.1 中还有更多好东西。元组、输出变量、抛出表达式、局部函数:我不确定没有它们我是如何编写代码的。
    • 具有讽刺意味的是,我在 EF6 名人 Julie Lerman 的视频中也发现了“反模式”:dddcommunity.org/ddd-contributors/… 不确定它是否作为反模式存在,但正是它引发了这篇文章。
    • 我非常爱朱莉。她真棒。但是,每个人都应该充分意识到,即使是专家,有时也会做一些愚蠢的事情。我们每个人都无法避免犯错。也就是说,我什至不会因为这个而责备她。正如我所说,如果有的话,不使用构造函数是一种微优化。虽然在构造函数中执行此操作在技术上是错误的,但实际上,您可以在大型应用程序中到处执行此操作,并且仍然不会真正导致任何显着的性能损失。
    • 好的,有道理。如果您也想对此进行抨击,我在第一个问题中添加了第二个问题。 用削尖的铅笔急切地坐着
    猜你喜欢
    • 2011-02-15
    • 2016-12-11
    • 2021-12-20
    • 2021-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-21
    • 1970-01-01
    相关资源
    最近更新 更多