恢复域对象的最佳方式

问题描述:

这是一个这样一个简单而常见的场景,我想知道我是如何管理的,直到现在我为什么还有问题。恢复域对象的最佳方式

我有这样的对象(基础设施组件的一部分)

public class Queue {} 

public class QueueItem 
{ 
    public QueueItem(int blogId,string name,Type command,object data) 
    { 
     if (name == null) throw new ArgumentNullException("name"); 
     if (command == null) throw new ArgumentNullException("command"); 
     BlogId = blogId; 
     CommandType = command; 
     ParamValue = data; 
     CommandName = name; 
     AddedOn = DateTime.UtcNow; 
    } 


    public Guid Id { get; internal set; } 
    public int BlogId { get; private set; } 
    public string CommandName { get; set; } 
    public Type CommandType { get; private set; } 
    public object ParamValue { get; private set; } 
    public DateTime AddedOn { get; private set; } 
    public DateTime? ExecutedOn { get; private set; } 
    public void ExecuteIn(ILifetimeScope ioc) 
    { 
     throw new NotImplementedException(); 
    } 
} 

这将在另一个组件来创建这样

​​

没有什么不同寻常这里。然而,这个对象将被发送到它将被持久保存的存储库中。队列对象将询问存储库中的项目。存储库应该重新创建QueueItem对象。

然而,正如你看到的,QueueItem性质不变,在创建项目时AddedOn属性应只设置一次。 Id属性将由Queue对象设置(这不重要)。

问题是我该如何重新创建存储库中的QueueItem?我可以有另一个构造函数,它将要求所有属性的每个值,但我不希望该构造函数可用于最初创建队列项目的程序集。该存储库是不同组件的一部分,因此内部不起作用。

我想过提供一个工厂方法 类QueueItem { /* ..rest的定义。*/

 public static QueueItem Restore(/* list of params*/){} 
    } 

至少清除意图,但我不知道为什么我不喜欢这种方法。我也可以仅通过Queue来强制创建项目,但这意味着要将Queue作为依赖项传递给repo,而这又不是我想要的。为此有一个特定的工厂对象,也似乎是矫枉过正。

基本上我的问题是:什么是重新创建资源库,对象不暴露特定造物功能到另一个消费对象的最佳途径。

更新

地注意到,仓库我指的是模式本身是一种抽象,而不是通过一个ORM的包装是很重要的。无论域对象如何或在何处保持不变。重要的是如何由存储库重新创建。另一个重要的事情是我的域模型是从持久性模型不同。我确实使用了RDBMS,但我认为这只是一个不应该承担任何重要性的实现细节,因为我正在寻找不依赖于特定存储访问的方式。

虽然这是一个特定的场景,但它基本上可以应用于将由回购恢复的每个对象。

UPDATE2

好吧,我不知道我能怎么样AutoMapper忘记。我错误的印象是它不能映射私人领域/ setter,但它可以,我认为这是最好的解决方案。

其实我可以说最佳的解决方案(IMO)是为了:

  1. 直接反序列化,如果有的话。
  2. Automap。
  3. 域对象本身的工厂方法。

前两个不需要对象做特别的事情,而第三个需要对象提供这种情况下的功能(一种输入有效状态数据的方法)。它有明确的意图,但它几乎做了一个映射工作。

回答更新

要回答自己,在这种情况下,最佳的方法是使用一个工厂方法。最初我选择了Automapper,但我发现自己更经常使用工厂方法。 Automapper有时会很有用,但在很多情况下这还不够。

+0

有点偏离主题,但如果这是你的“域”的一部分,你可能要考虑一个像NServiceBus或MassTransit这样的工具。 – 2012-12-28 02:02:13

一个ORM框架会照顾你。你只需要告诉它重新水化一个对象,并且域类的常规实例将被提供给你(有时你只需要声明属性为虚拟或者受保护,例如在NHibernate中)。原因是因为在引擎盖下,它们通常在从您的基类派生的代理对象上运行,从而允许您保持这些基类不变。

如果你想实现自己的持久层,这是一个完整的故事。在不破坏原始定义在对象中的范围限制的情况下,从数据库中再补充对象可能涉及反射。你还必须考虑很多侧面的问题:如果你的物体有一个对另一个物体的引用,你必须先补充那一个,等等。

你可以看看那个教程:Build Your Own dataAccess Layer虽然我不会建议在大多数情况下重新发明*。

+0

该问题不依赖于数据库。当我说知识库时,我的意思是说它完全是一种抽象。即使使用ORM,我仍然必须将orm实体映射到域实体。我已经更新了我的初步问题,并提供了这个说明 – MikeSW 2012-04-06 13:58:07

+0

然后我猜你只有在YourReposAssembly中有这些选项:内部关键字+ [InternalsVisibleTo(YourReposAssembly)] *或* Reflection *或* Restore()方法*或*子类QueueItem。 .. – guillaume31 2012-04-06 14:22:36

+0

感谢您的建议,但我认为我找到了最适合自己的方式。我更新了这个问题。 – MikeSW 2012-04-06 14:53:36

你谈到了对象本身的工厂方法。但DDD指出实体应该由工厂创建。所以你应该有一个QueueItemFactory可以创建新的QueueItem并且恢复现有的QueueItems。

好吧我不知道我怎么能忘记AutoMapper。

我希望我能忘记AutoMapper。只是看着可怕的API让我不寒而栗。

+0

在这种情况下,工厂对CREATE实体来说是一个很好的选择。但在这里我想要恢复,这是存储库的责任。我不认为工厂应该恢复一个实体。有几种方法可以进行恢复,目前我更喜欢实体本身的静态工厂方法。 – MikeSW 2012-07-23 17:44:13

+0

实际上,存储库将工作委托给工厂(如果要恢复对象,您也需要一个实例)。如果你要做CQRS,仓库可能会将工作委派给重放该对象上的域事件的东西。存储库只是一个保存聚合根源列表的集合。在你的情况下,存储库将有几个不同的职责(即改变原因)。这就是说,大多数人已经使用NHibernate;这使得不需要存储库 – Jeroen 2012-07-24 07:50:01

+0

我不同意。回购可能会将工作委托给工厂,但我不明白为什么工厂应该处理恢复,这是一个持久性概念。在给定状态或事件流的情况下,对象(或构造函数中的事件)最多可以重新创建对象。存储库被视为一个集合,它们是一个外观,它们不仅仅是一个简单的列表。 ORM是DAL的实现细节,可以由存储库使用,但就是这样。 NH处理持久性模型,存储库返回域对象。不同的责任。 – MikeSW 2012-07-24 13:19:21