Это такой простой и распространенный сценарий, что мне интересно, как я справлялся до сих пор и почему у меня сейчас проблемы.
У меня есть этот объект (часть сборки Infrastructure)
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();
}
}
Это будет создано в другой сборке, подобной этой
var qi = new QueueItem(1,"myname",typeof(MyCommand),null);
Здесь нет ничего необычного. Однако этот объект будет отправлен в репозиторий, где он будет сохранен. Объект Queue будет запрашивать у репозитория элементы. Репозиторий должен заново создавать объекты QueueItem.
Однако, как видите, свойства QueueItem неизменны, свойство AddedOn должно быть задано только один раз при создании элемента. Свойство Id будет установлено объектом Queue (это не важно).
Вопрос в том, как мне воссоздать QueueItem в репозитории? У меня может быть другой конструктор, который потребует каждое значение для ВСЕХ свойств, но я не хочу, чтобы этот конструктор был доступен для сборки, которая первоначально создаст элемент очереди. Репозиторий является частью другой сборки, поэтому внутренний не будет работать.
Я подумал о предоставлении фабричного метода class QueueItem { /* ..остальные определения.. */
public static QueueItem Restore(/* list of params*/){}
}
что, по крайней мере, очищает намерение, но я не знаю, почему мне не нравится этот подход. Я также мог бы принудительно создать элемент только с помощью Queue , но это означает передать Queue как зависимость от репо, что опять же не то, что мне бы хотелось. Наличие для этого конкретного фабричного объекта также кажется излишним.
По сути, мой вопрос заключается в следующем: какой оптимальный способ воссоздать объект в репозитории, не подвергая эту конкретную функцию создания другому потребительскому объекту.
Обновить
Важно отметить, что под репозиторием я подразумеваю сам шаблон как абстракцию, а не оболочку над ORM. Неважно, как и где сохраняются объекты домена. Имеет значение, как может быть воссоздан репозиторий. Еще одна важная вещь заключается в том, что моя модель домена отличается от модели постоянства. Я использую СУБД, но я думаю, что это просто деталь реализации, которая не должна иметь никакого значения, так как я ищу способ, который не зависит от конкретного доступа к хранилищу.
Хотя это конкретный сценарий, он может применяться практически к каждому объекту, который будет восстановлен репозиторием.
Обновление 2
Хорошо, я не знаю, как я мог забыть об AutoMapper. У меня сложилось неправильное впечатление, что он не может отображать частные поля/установщики, но может, и я думаю, что это лучшее решение.
На самом деле я могу сказать, что оптимальные решения (IMO) в порядке:
- Прямая десериализация, если она доступна.
- Автокарта.
- Фабричный метод самого объекта домена.
Первые два не требуют, чтобы объект делал что-то конкретное, в то время как третий требует, чтобы объект предоставлял функциональные возможности для этого случая (способ ввода допустимых данных состояния). У него четкие намерения, но он в значительной степени выполняет работу картографа.
Ответ Обновлен
Чтобы ответить себе, в этом случае оптимальным способом является использование фабричного метода. Первоначально я выбрал Automapper, но чаще использовал фабричный метод. Иногда Automapper может быть полезен, но во многих случаях этого недостаточно.