DDD にリファクタリングしようとしているシナリオがあります。BatchEntries の集約とリストであるバッチがあります。バッチが作成され、BatchEntries が追加された後、SMS がバッチ内の個人に送信され、バッチのステータスが実行中から投稿済みに変わります。
デザインをより良くするためのアイデアはありますか?ドメインには 2 つの集約 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 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));
}
}
質問:
- Running、Posted などの BatchStatus をどこに割り当てる必要がありますか?
- MarkBatchAsPosted メソッドを Batch エンティティのメソッドとして定義する必要がありますか?
- ドメイン駆動設計のためにこれを再設計するにはどうすればよいでしょうか?