3

This is such a simple and common scenario I wonder how did I managed until now and why I have problems now.

I have this object (part of the Infrastructure assembly)

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();
    }
}

This will be created in another assembly like this

 var qi = new QueueItem(1,"myname",typeof(MyCommand),null);

Nothing unusal here. However, this object will be sent t oa repository where it will be persisted.The Queue object will ask the repository for items. The repository should re-create QueueItem objects.

However, as you see, the QueueItem properties are invariable, the AddedOn property should be set only once when the item is created. The Id property will be set by the Queue object (this is not important).

The question is how should I recreate the QueueItem in the repository? I can have another constructor which will require every value for ALL the properties, but I don't want that constructor available for the assembly that will create the queue item initially. The repository is part of a different assembly so internal won't work.

I thought about providing a factory method class QueueItem { /* ..rest of definitions.. */

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

which at least clears the intent, but I don't know why I don't like this approach. I could also enforce the item creation only by the Queue , but that means to pass the Queue as a dependency to the repo which again isn't something I'd like. To have a specific factory object for this, also seems way overkill.

Basically my question is: what is the optimum way to recreate an object in the repository, without exposing that specific creational functionality to another consumer object.

Update

It's important to note that by repository I mean the pattern itself as an abstraction, not a wrapper over an ORM. It doesn't matter how or where the domain objects are persisted. It matters how can be re-created by the repository. Another important thing is that my domain model is different from the persistence model. I do use a RDBMS but I think this is just an implementation detail which should not bear any importance, since I'm looking for way that doesn't depend on a specific storage access.

While this is a specific scenario, it can applied to basically every object that will be restored by the repo.

Update2

Ok I don't know how I could forget about AutoMapper. I was under the wrong impression it can't map private fields/setter but it can, and I think this is the best solution.

In fact I can say the optimum solutions (IMO) are in order:

  1. Directly deserializing, if available.
  2. Automap.
  3. Factory method on the domain object itself.

The first two don't require the object to do anyting in particular, while the third requires the object to provide functionality for that case (a way to enter valid state data). It has clear intent but it pretty much does a mapper job.

Answer Updated

To answer myself, in this case the optimum way is to use a factory method. Initially I opted for the Automapper but I found myself using the factory method more often. Automapper can be useful sometimes but in quite a lot of cases it's not enough.

4

2 回答 2

0

ORM 框架会为您解决这个问题。您只需要告诉它重新水化一个对象,然后域类的常规实例就会提供给您(有时您只需将属性声明为虚拟或受保护,例如在 NHibernate 中)。原因是因为在幕后,它们通常对派生自您的基类的代理对象进行操作,从而使您可以保持这些基类的完整性。

但是,如果您想实现自己的持久层,那就另当别论了。在不破坏对象中最初定义的范围约束的情况下从数据库中重新水化对象可能涉及反射。您还必须考虑很多附带的问题:如果您的对象引用了另一个对象,则必须先重新水化该对象,等等。

您可以查看该教程:构建您自己的数据访问层,尽管我不建议在大多数情况下重新发明轮子。

于 2012-04-06T13:22:13.127 回答
0

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

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

我希望我能忘记 AutoMapper。只是看着可怕的 API 就让我脊背发凉。

于 2012-07-23T15:08:38.613 回答