1

我正在使用域驱动设计方法开发 Web 应用程序,但是我的应用程序的某些方面不适合 DDD。例如,我们需要批量更新员工工资。加载整个员工实体并为每个员工保存它是效率不高的,因为通常一次更新数百个薪水。此外,还需要同时执行其他任务,例如记录旧工资和记录新工资的生效日期。所以我会说这种类型的操作超出了我的核心域的有界上下文。此外,我了解,最好从程序的角度来处理此操作。这一切都很好

例如,我正在使用以下结构。

  • 用户界面
  • 应用
  • 模型
  • 基础设施

即使对于我的核心领域的有界上下文之外的事情,我也想坚持这种结构。我现在主要关心的是我的基础设施层。最初我在基础设施中使用以下内容:

  • 存储库
  • 查找器(用于单独的读取模型)
  • 命令

我在 Finders 中放置了 ad-hoc 读取查询,在 Commands 中放置了 ad-hoc 命令。这样做的问题是某些操作需要一系列查询和命令,对我来说,将它们全部组合在一个单元中似乎更有条理。有点像存储库,但它不是提供对域实体的访问,而是封装了一组构成特定过程的查询和命令。

所以我正在寻找的是重新命名约定的建议,以将“命令”文件夹/命名空间更改为更好地描述一系列逻辑上适合的查询/命令。是否已经有我不知道的名称/模式?

更新:

我目前正在考虑使用命名空间“程序”来描述这些逻辑上组合在一起的查询/命令。一方面它是合适的,因为我所描述的类似于存储过程,并且描述性的是应用程序的这一部分使用的是过程而不是 DDD 方法。我唯一的疑虑是这种命名约定意味着使用存储过程,但事实并非如此。

4

3 回答 3

3

首先阅读这篇文章,它可以帮助您进行批量更新。IMO薪水不是员工定义的一部分,我会说薪水是相关的或需要员工(作为c的参考)。

更改薪水是域用例,而保持旧薪水似乎是域规则。他们确实想保留所有旧工资吗?这不是技术决策,而是商业决策。就个人而言,我不认为这是程序心态的情况。

关于同时需要查询和命令的操作。命令是改变域的东西。你说这些命令/查询构成了一个特定的过程。什么的?您似乎在描述一个用例。它是域已知的东西吗?它需要业务逻辑吗?还是严格意义上的持久性或基础设施相关(更新一些读取模型,查询其他读取模型)?如果有逻辑,则表明您可能有服务。如果是业务逻辑,它可能是业务概念或用例,因此它们属于域。如果它的持久性逻辑属于 DAL,如果它是 UI 逻辑,那么它属于 UI 等等。

更新 评论太长了

这篇文章的重点是,如果您需要对域实体进行批量处理,那么在 99% 的情况下,您使用的是错误的模型。在您的情况下,员工与工资之间的关系确实很重要。我会说(只是一个非常模糊的建议)你可以有一个 SalariesManager (坏名字..),它将员工(id)与从特定日期开始的薪水相关联。

 public interface IManageSalaries
 {
      void ChangeEmployeeSalary(Guid employee, Salary newSalary,DateTime startingFrom);

     //possible bulk operation
      void ChangeSalary(Guid[] employees, Salary newSalary,DateTime startingFrom);          

      SalaryInfo[] GetSalaryHistory(Guid employeeId);
      Salary GetCurrentSalary(Guid employeeId);
 }

该实现只会向表中添加一个新的(employee_id、salary、date)。您更改了当前工资,但也保留了旧条目。接口可以是 Domain 的一部分,但实现是 Persistence 的一部分(因为它很简单并且不包含业务逻辑)。想想看,它确实看起来像一个存储库,但没有聚合根。

但这只是一个建议。我觉得还有另一种更适合域的解决方案。由您和领域专家来识别它。

于 2014-06-11T14:21:20.480 回答
0

应用程序责任中的命令/查询,查看六边形架构。您可以将临时命令和查询作为适配器/端口添加到您的应用程序

于 2014-05-29T15:12:37.010 回答
0

我让我的存储库能够开始事务,然后将 TransactionCommand 传递给所有涉及的存储库。一旦最终存储库完成更新,我就会提交它。这样,我仍然可以使用我现有的存储库(基本上每个模型/实体一个),而无需编写临时/自定义查询。

我只希望我自己的模型/实体实现存储库接口,而不是为每个定义一个单独的存储库。前者将允许多态存储库操作,而后者则不允许。生活和燃烧。

这是事务存储库的用法,该方法取自 Entity1Service 类(我的服务层,每个实体一个类,包含使用一个或多个存储库来完成某些目标的静态方法)

public class Entity1Service
{
    public static bool WriteEntity1(Entity1 entity1)
    {
        Entity1RepositorySQLite sqlRepo = new Entity1RepositorySQLite();

        sqlRepo.BeginTransaction(); 

        int entity1Id;

        if (!LocalIdService.ReadAndIncrementEntity1Id(out entity1Id, sqlRepo.TransactionCommand))
        {
            sqlRepo.RollbackTransaction();

            return false;
        }   

        int entity1IdOld = entity1.Id;  

        try
        {
            IdMapService.CreateMapEntity1Id(entity1Id, entity1Id, sqlRepo.TransactionCommand);

            entity1.Id = entity1Id;

            sqlRepo.Write(attachment);
        }
        catch (Exception)
        {
            sqlRepo.RollbackTransaction();

            attachment.Entity1Id = attachmentIdOld;     

            throw;
        }   

        sqlRepo.EndTransaction();

        return true;
    }
}

存储库定义

public interface ITransaction
{
    SqliteCommand TransactionCommand { get; set; }
    bool InTransaction { get; }

    void BeginTransaction();
    void RollbackTransaction();
    void CloseTransaction();
    void EndTransaction();
}

public class RepositorySQLiteTransactional<T> : RepositorySQLite<T>, ITransaction where T : new()
{    
    public RepositorySQLiteTransactional(IDataMapperSQLite<T, string[]> dataMapper) : base(dataMapper) { }     

    public RepositorySQLiteTransactional(IDataMapperSQLite<T, string[]> dataMapper, SqliteCommand transactionCommand) : this(dataMapper)        
    {            
        _dbLayer.DblTransactionCommand = transactionCommand;
    }

    public SqliteCommand TransactionCommand
    {            
        get { return (SqliteCommand)_dbLayer.DblTransactionCommand; }
        set
        {
            _dbLayer.DblTransactionCommand = value;
        }
    }

    public bool InTransaction
    {
        get { return _dbLayer.DblInTransaction; }
    }       

    public void BeginTransaction()        
    {
        try
        {
            _dbLayer.DblBeginTransaction();
        }
        catch( Exception )           
        {
            _dbLayer.DblCloseTransaction();

            throw;
        }
    }

    public void RollbackTransaction()
    {
        _dbLayer.DblRollbackTransaction();
    }

    public void CloseTransaction()
    {
        _dbLayer.DblCloseTransaction();
    }

    public void EndTransaction()
    {
        _dbLayer.DblEndTransaction();         
    }
}    

public interface IRepository<T>
{        
    List<T> Read(IConditions conditions);     

    T FindOne(IQuery query);
    List<T> FindAll(IQuery query);

    void WriteOne(T obj);
    void WriteOne(T obj, out int newId);
    void WriteOne(IQuery query);
    void WriteAll(List<T> objs);

    void UpdateOne(T obj);
    void UpdateAll(List<T> objs);        
    void UpdateOne(IQuery query);

    void ReplaceAll(List<T> objs);

    void DeleteAll();
    void DeleteAll(List<T> objs);

    //void Add(T entity);
    //void Delete(T entity);
    //void Edit(T entity);
    //void Save();
}

public class RepositorySQLite<T> : IRepository<T> where T : new()
{
    protected AndroidDB _dbLayer;
    protected IDataMapperSQLite<T, string[]> _dataMapper;

    private RepositorySQLite()  // force data mapper init
    {

    }

    public RepositorySQLite(IDataMapperSQLite<T, string[]> dataMapper)
    {

    }

    public List<T> Read(IConditions conditions) { throw new NotImplementedException(); }
    public void WriteOne(T obj, out int newId) { throw new NotImplementedException(); }
    public void WriteOne(IQuery query) { throw new NotImplementedException(); }

    private void ClearMapState()
    {

    }

    public void ReplaceAll(List<T> objs)
    {

    }

    public void WriteAll(List<T> objList)
    {

    }

    public void WriteOne(T obj)
    {

    }

    public void UpdateOne(T obj)
    {

    }

    public void UpdateAll(List<T> objs)
    {

    }

    public void UpdateOne(IQuery query)
    {

    }

    public T FindOne(IQuery query)
    {

    }

    public List<T> FindAll(IQuery query)
    {

    }

    public void DeleteAll(List<T> objs)
    {  

    }

    public void DeleteAll()
    {           

    }

    public void DeleteAll( IQuery query )
    {            

    }    
}
于 2014-06-11T13:33:37.303 回答