【问题标题】:Save Me on a Business Object将我保存在业务对象上
【发布时间】:2010-11-14 22:37:24
【问题描述】:

我经常在业务对象上看到这样的例子:

public void Save()
{
     if(this.id > 0)
     {
          ThingyRepository.UpdateThingy(this);
     }
     else
     {
          int id = 0;
          ThingyRepository.AddThingy(this, out id);
          this.id = id;
     }
}

那么为什么在这里,在业务对象上?这似乎与上下文或数据相关,而不是业务逻辑。

例如,这个对象的消费者可能会经历这样的事情......

...Get form values from a web app...

Thingy thingy = Thingy.CreateNew(Form["name"].Value, Form["gadget"].Value, Form["process"].Value);
thingy.Save();

或者,类似这样的更新......

... Get form values from a web app...

Thingy thingy = Thingy.GetThingyByID(Int32.Parse(Form["id"].Value));
Thingy.Name = Form["name"].Value;
Thingy.Save();

那为什么会这样呢?为什么不包含实际的业务逻辑,例如计算、业务特定规则等,并避免检索/持久化?

使用这种方法,代码可能如下所示:

... Get form values from a web app...

Thingy thingy = Thingy.CreateNew(Form["name"].Value, Form["gadget"].Value, Form["process"].Value);
ThingyRepository.AddThingy(ref thingy, out id);

或者,类似这样的更新......

... get form values from a web app ...

Thingy thingy = ThingyRepository.GetThingyByID(Int32.Parse(Form["id"].Value));
thingy.Name = Form["Name"].Value;
ThingyRepository.UpdateThingy(ref thingy);

在这两个示例中,最了解对象正在做什么的消费者调用存储库并请求添加或更新。该对象在该上下文中仍然是 DUMB,但仍提供与其自身相关的核心业务逻辑,而不是如何检索或保留它。

简而言之,我没有看到在业务对象本身中整合 GET 和 SAVE 方法的好处。

我应该停止抱怨和顺从,还是我错过了什么?

【问题讨论】:

    标签: c# domain-driven-design business-objects


    【解决方案1】:

    这会导致Active Record pattern(参见P of EAA p. 160)。

    我个人不是粉丝。紧密耦合业务对象和持久性机制,以便更改持久性机制需要更改业务对象?将数据层与域层混合?违反single responsibility principle?如果我的业务对象是Account,那么我有实例方法Account.Save,但要查找帐户我有静态方法Account.Find?好恶心。

    也就是说,它有它的用途。对于具有直接符合数据库模式的对象并且具有简单的域逻辑并且不关心易于测试、重构、依赖注入、打开/关闭、关注点分离等的小型项目,它可能是一个不错的选择。

    【讨论】:

    • 没错,这真的归结为 Active Record 与域模型。每个人都有自己的位置、优势和劣势。
    【解决方案2】:

    您的域对象不应引用持久性问题。

    在域中创建一个代表持久化服务的存储库接口,并在域外实现它(您可以在单独的程序集中实现它)。

    这样,您的聚合根不需要引用存储库(因为它是聚合根,它应该已经拥有所需的一切),并且它不会有任何依赖或持久性问题。因此更容易测试,并且专注于领域。

    【讨论】:

      【解决方案3】:

      虽然我不了解 DDD,但有 1 种方法是有意义的(它将执行 UPSERT。如果记录不存在则插入,否则更新)。

      该类的用户可以装傻,在现有记录上调用 Save 并在新记录上调用 Update。 有一个行动点要清楚得多。

      编辑:是否执行 INSERT 或 UPDATE 的决定最好留给存储库。用户可以调用 Repository.Save(....),这可能会导致新记录(如果记录尚未在数据库中)或更新。

      【讨论】:

        【解决方案4】:

        如果您不喜欢他们的方法,请自行选择。个人对业务对象的 Save() 实例方法对我来说真的很好闻。我需要记住的班级名称少了一个。但是,我对工厂保存没有问题,但我不明白为什么两者都很难。浏览器

        class myObject
        {
           public Save()
           {
              myObjFactory.Save(this);
           }
        }
        ...
        
        class myObjectFactory
        {
           public void Save(myObject obj)
           {
              // Upsert myObject   
           }
        }
        

        【讨论】:

          猜你喜欢
          • 2015-07-07
          • 2013-12-02
          • 1970-01-01
          • 1970-01-01
          • 2012-03-28
          • 2014-03-14
          • 1970-01-01
          • 1970-01-01
          • 2019-06-09
          相关资源
          最近更新 更多