Бизнес-модель Entity Framework для модели персистентности DDD - PullRequest
0 голосов
/ 09 марта 2020

Я уже некоторое время борюсь с проблемой, для которой я не могу найти лучшее решение.

Это первый проект, в котором я хочу использовать шаблон проектирования, управляемый доменом, на самом деле это просто демонстрация проект, который я использую, чтобы улучшить свои навыки кодирования.

Мой проект (настольное приложение WPF) довольно прост и просто сохраняет проекты в базе данных. Каждый проект может иметь несколько пробелов (1: n). Все первичные ключи генерируются базой данных. Поэтому я создал простую модель постоянства:

public class Project
{
    public int Id                { get; set; }
    public string Name           { get; set; }
    public string Description    { get; set; }
    public string Owner          { get; set; }
    public DateTime CreationDate { get; set; }

    public ICollection<Space> Spaces { get; set; }
}

public class Space
{
    public int Id      { get; set; }
    public string Name { get; set; }

    public int ProjectId   { get; set; }
    public Project Project { get; set; }
}

Я также создаю модель предметной области, которая будет содержать некоторые бизнес-логики c, сейчас она просто выглядит как модель постоянства.

public interface IIdentifiable
{
    public int Id { get; }
}

public class Project : IIdentifiable
{
    public int Id                { get; set; }
    public string Name           { get; set; }
    public string Description    { get; set; }
    public string Owner          { get; set; }
    public DateTime CreationDate { get; set; }

    public ICollection<Space> Spaces { get; set; } = new List<Space>();
}

public class Space : IIdentifiable
{
    public int Id      { get; set; }
    public string Name { get; set; }

    public Project Project { get; set; }
}

После этого я создал службу «хранения», в которой будут методы для добавления / обновления / удаления сущностей.

Я разработал службу, которая принимает модели предметной области и преобразует их в модели постоянства (используя automapper). Я хочу иметь возможность добавлять / обновлять / удалять сущности без немедленного сохранения изменений.

Поэтому я создал абстрактный класс, который предоставляет мне все эти функции для каждого типа домена.

public class MyDbSet<TEntity, TDomain> where TEntity : class
                                           where TDomain : class, IIdentifiable
{
    protected readonly RemotingContext _context;
    protected readonly IMapper _mapper;
    protected readonly DbSet<TEntity> _entities;

    public RemotingSet(RemotingContext context, IMapper mapper)
    {
        _context    = context;
        _mapper     = mapper;
        _entities   = _context.Set<TEntity>();
    }

    public void AddAsync(TDomain item)
    {
        var entity = _mapper.Map<TEntity>(item);
        _entities.Add(entity);
    }

    public async Task Update(TDomain item)
    {
        var entity = await _entities.FindAsync(item.Id);

        if (entity != null)
            _mapper.Map(item, entity);
    }

    public async Task<bool> TryRemove(TDomain item)
    {
        var entity = await _entities.FindAsync(item.Id);

        if (entity != null)
        {
            _entities.Remove(entity);
            return true;
        }

        return false;
    }
}

и наконец, мой класс хранения, который содержит MySet для каждого типа модели домена:

public class Storage:IDisposable
{
    private readonly IMapper _mapper;
    private readonly MyContext _context;

    public Projects Projects { get; private set; }
    public Spaces Spaces     { get; private set; }

    public Storage()
    {
        _context = new MyContext();
        _mapper = new MapperConfiguration(cfg => cfg.AddProfile(new Config.RemotingProfile())).CreateMapper();

        Projects = new Projects(_context, _mapper);
        Spaces   = new Spaces(_context, _mapper);
    }

    public Task<int> SaveChanges()
    {
        return _context.SaveChangesAsync();
    }

    public void Dispose()
    {
        _context.Dispose();
    }
}

public class Projects : MySet<Persistence.Models.Project, Domain.Models.Project>
{
    public Projects(MyContext context, IMapper mapper) : base(context, mapper) { }

    public async Task<IEnumerable<Project>> Get()
    {
        return _mapper.Map<IEnumerable<Project>>(await _context.dbsProjects.Include(p => p.Spaces).ToListAsync());
    }
}

public class Spaces : MySet<Persistence.Models.Space, Domain.Models.Space>
{
    public Spaces(MyContext context, IMapper mapper) : base(context, mapper) { }
}

Моя конфигурация Automapper выглядит следующим образом:

public class MyProfile : Profile
{
    public MyProfile()
    {
        CreateMap<Persistence.Models.Project, Domain.Models.Project>().ReverseMap();
        CreateMap<Persistence.Models.Space, Domain.Models.Space>().ReverseMap();
    }
}

Итак, теперь моя проблема: как упоминалось выше, сохранение базы данных будет сделано не сразу, а когда пользователь захочет. Означает, что когда я добавляю проект и впоследствии обновляю его (например, изменяю имя), этот метод обновления не найдет проект, так как у него пока нет установленного идентификатора, поскольку save не был вызван.

Если я позвоню сохранить после добавления, а затем обновить проект, все работает как положено.

Мой вопрос: как я могу использовать Entity Framework и его поведение отслеживания изменений в таком сценарии? Я не знаю, правильно ли я иду в реализации такого дизайна.

Буду очень признателен за вашу помощь в этом. Как уже говорилось, я впервые пытаюсь реализовать такой дизайн, поэтому, если мой подход совершенно неправильный, я также буду рад получить совет о том, как сделать это правильно.

Мануэль

...