问题
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:
- Directly deserializing, if available.
- Automap.
- 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.
回答1:
An ORM framework would take care of that for you. You just have to tell it to rehydrate an object and a regular instance of the domain class will be served to you (sometimes you only have to declare properties as virtual or protected, in NHibernate for instance). The reason is because under the hood, they usually operate on proxy objects derived from your base classes, allowing you to keep these base classes intact.
If you want to implement your own persistence layer though, it's a whole nother story. Rehydrating an object from the database without breaking the scope constraints originally defined in the object is likely to involve reflection. You also have to think about a lot of side concerns : if your object has a reference to another object, you must rehydrate that one before, etc.
You can have a look at that tutorial : Build Your Own dataAccess Layer although I wouldn't recommend reinventing the wheel in most cases.
回答2:
You talked about a factory method on the object itself. But DDD states that entities should be created by a factory. So you should have a QueueItemFactory that can create new QueueItems and restore existing QueueItems.
Ok I don't know how I could forget about AutoMapper.
I wish I could forget about AutoMapper. Just looking at the hideous API gives me shivers down my spine.
来源:https://stackoverflow.com/questions/10040950/optimum-way-to-restore-domain-object