У меня есть сценарий, который пытается реорганизовать DDD. У меня есть пакет, который является агрегатом и List of BatchEntries. После создания пакета и добавления BatchEntries, сообщение отправляется отдельным лицам в партии, а статус изменений партии - от запущенных до отправленных.Рефакторинг для управления доменом
Любые идеи о том, как сделать дизайн лучше? В домене есть два агрегата Batch и BatchEntry, причем Batch является агрегированным корнем.
код выглядит следующим образом
public class Batch : EntityBase, IValidatableObject
{
public int BatchNumber { get; set; }
public string Description { get; set; }
public decimal TotalValue { get; set; }
public bool SMSAlert { get; set; }
public int Status { get; set; }
private HashSet<BatchEntry> _batchEntries;
public virtual ICollection<BatchEntry> BatchEntries
{
get{
if (_batchEntries == null){
_batchEntries = new HashSet<BatchEntry>();
}
return _batchEntries;
}
private set {
_batchEntries = new HashSet<BatchEntry>(value);
}
}
public static Batch Create(string description, decimal totalValue, bool smsAlert)
{
var batch = new Batch();
batch.GenerateNewIdentity();
batch.Description = description;
batch.TotalValue = totalValue;
batch.SMSAlert = smsAlert;
return batch;
}
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
//
}
}
public interface IBatchRepository : IRepository<Batch>
{
int NextBatchNumber();
}
public class BatchEntry : EntityBase, IValidatableObject
{
public Guid BatchId { get; set; }
public virtual Batch Batch { get; private set; }
public decimal Amount { get; set; }
public Guid CustomerAccountId { get; set; }
public virtual CustomerAccount CustomerAccount { get; private set; }
public static BatchEntry Create(Guid batchId, Guid customerAccountId, decimal amount)
{
var batchEntry = new BatchEntry();
batchEntry.GenerateNewIdentity();
batchEntry.BatchId = batchId;
batchEntry.CustomerAccountId = customerAccountId;
batchEntry.Amount = amount;
return batchEntry;
}
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
//
}
}
public interface IBatchEntryRepository : IRepository<BatchEntry>{}
домен и доменные службы подвергаются с помощью Application Services. Кодекс в прикладных услуг выглядит следующим образом:
//Application Services Code
public class BatchApplicationService : IBatchApplicationService
{
private readonly IBatchRepository _batchRepository;
private readonly IBatchEntryRepository _batchEntryRepository;
public BatchAppService(IBatchRepository batchRepository, IBatchEntryRepository batchEntryRepository)
{
if (batchRepository == null) throw new ArgumentNullException("batchRepository");
if (batchEntryRepository == null) throw new ArgumentNullException("batchEntryRepository");
_batchRepository = batchRepository;
_batchEntryRepository = batchEntryRepository;
}
public BatchDTO AddNewBatch(BatchDto batchDto)
{
if (batchDto != null)
{
var batch = Batch.Create(batchDto.Description, batchDto.TotalValue, batchDto.SMSAlert);
batch.BatchNumber = _batchRepository.NextBatchNumber();
batch.Status = (int)BatchStatus.Running;
SaveBatch(batch);
return batch.Map<BatchDto>();
}
else
{
//
}
}
public bool UpdateBatch(BatchDto batchDto)
{
if (batchDto == null || batchDto.Id == Guid.Empty)
{
//
}
var persisted = _batchRepository.Get(batchDto.Id);
if (persisted != null)
{
var result = false;
var current = Batch.Create(batchDto.Description, batchDto.TotalValue, batchDto.SMSAlert);
current.ChangeCurrentIdentity(persisted.Id);
current.BatchNumber = persisted.BatchNumber;
current.Status = persisted.Status;
_batchRepository.Merge(persisted, current);
_batchRepository.UnitOfWork.Commit();
if (persisted.BatchEntries.Count != 0){
persisted.BatchEntries.ToList().ForEach(x => _batchEntryRepository.Remove(x));
_batchEntryRepository.UnitOfWork.Commit();
}
if (batchDto.BatchEntries != null && batchDto.BatchEntries.Any())
{
List<BatchEntry> batchEntries = new List<BatchEntry>();
int counter = default(int);
batchDTO.BatchEntries.ToList().ForEach(x =>
{
var batchEntry = BatchEntry.Create(persisted.Id, x.CustomerAccountId, x.Amount);
batchEntries.Add(batchEntry);
});
}
else result = true;
return result;
}
else
{
//
}
}
public bool MarkBatchAsPosted(BatchDto batchDto, int authStatus)
{
var result = false;
if (batchDto == null || batchDto.Id == Guid.Empty)
{
//
}
var persisted = _batchRepository.Get(batchDto.Id);
if (persisted != null)
{
var current = Batch.Create(batchDto.Description, batchDto.TotalValue, batchDto.SMSAlert);
current.ChangeCurrentIdentity(persisted.Id);
current.BatchNumber = persisted.BatchNumber;
current.Status = authStatus;
_batchRepository.Merge(persisted, current);
_batchRepository.UnitOfWork.Commit();
result = true;
}
else
{
//
}
return result;
}
private void SaveBatch(Batch batch)
{
var validator = EntityValidatorFactory.CreateValidator();
if (validator.IsValid<Batch>(batch))
{
_batchRepository.Add(batch);
_batchRepository.UnitOfWork.Commit();
}
else throw new ApplicationValidationErrorsException(validator.GetInvalidMessages(batch));
}
}
Вопросы:
- Где должен BatchStatus Running т.е., Опубликовано быть назначены?
- Должен ли метод MarkBatchAsPosted быть определен как меход в пакетной сущности?
- Насколько лучше это можно переделать для управляемого доменом дизайна?
это довольно хорошо читать. У меня есть много информации, которая поможет в моем рефакторинге. Thanx – mkaris
@mkaris Я рад помочь. Если у вас есть более конкретные вопросы, дайте мне знать. – plalx
Я бы отреагировал на **, что для меня очень мало смысла. Может ли партия быть партией без каких-либо записей? Если нет, то почему пакет автоматически запускается при добавлении записей? ** В бизнес-правиле оговаривается, что пакет создается без позиций, но должен иметь хотя бы описание, batchnumber и totalvalue и статус (Ожидание - от запуска после серьезного думал). Записи добавляются позже на более позднем этапе. Значение партикуляции будет использоваться для проверки того, полностью ли выделена партия. Когда это будет сохранено (обновить записи), статус будет изменен на отправленный. – mkaris