是否可以在域模型上创建不可变的 属性?

Is it possible to create an immutable property on a domain model?

我们有许多逻辑域对象都驻留在同一个物理数据库中 table WorkStep。 sql table 中元数据的一个简单示例是 ID |NAME| TYPE,这样 TYPE 是定义可能类型的 table 的 FK。然而,一旦从数据库中选择,每一行可能代表一个不同的域模型,必须应用非常不同的业务规则。我现在使用的业务规则是,一旦创建,WorkStepType 属性 这些对象之一就不能 永远 更改。所以,任何对此的调用都会导致 this 发生变化,这将是一件非常糟糕的事情。

那么,是否有可能制作一个可以通过 automapper 和 dapper 等附加组件构造的对象,并且可以设置一次 属性。并且从未改变?此外,类型不能相互转换。

我没有尝试太多,我什至不确定是否可以在没有 hacky 代码的情况下做到这一点

我认为这是两个独立的操作。

第一个是 return 可用的 WorkStepType 个对象列表,第二个是将其分配为 "workflow" [=] 上的不可变 属性 40=] 为您的不同对象公开通用类型。

注意 - 语法为 C#6。不确定 VB.NET 等价物是什么。

例子

public class WorkStepType 
{
    // immutable properties
    public int Id { get; }
    public string Name { get; }

    public WorkStepType(int id, string name)
    {
        this.Id = id;
        this.Name = name;
    }
}

而通用 class 为

public class Workflow<T>
{
    public WorkStepType WorkStep { get; }
    public T DomainModel { get; }

    public Workflow(WorkStepType type, T domainModel)
    {
        this.WorkStep = type;
        this.DomainModel = domainModel;
    }
}

你如何选择水化这些物体取决于你。如果您使用 Drapper(建立在 Dapper 之上),您可能有一个类似于下面的存储库 class(尽管我提倡为 WorkStepType/Workflows 使用单独的 CRUD 存储库,这是为了说明这个想法)

public class WorkflowRepository
{
    // IDbCommander is a Drapper construct. 
    private readonly IDbCommander _commander;

    public WorkflowRepository(IDbCommander commander)
    {
        this._commander = commander;
    }

    public IEnumerable<WorkStepType> RetrieveAllWorkSteps()
    {
        // return all the available workstep types available 
        // to the user/application
        return _commander.Query<WorkStepType>();
    }

    public Workflow Retrieve(WorkStepType type)
    {
        // lookup the specific domain model for the supplied
        // workstep type. 
        var domainModel = _commander.Query<Workflow>(new { id = type.Id }).SingleOrDefault();
        return new Workflow(type, domainModel);
    }
}

这种方法应该会为您提供您正在寻找的行为,并且证明是高度可测试的。

您可能希望公开设置域模型,具体取决于您是否打算将新实例分配给现有 WorkStepType。不确定你的 design/needs 但我相信你明白了要点。

希望对您有所帮助。

Dapper 映射到私有属性(或私有 setters/mutators)。

public class WorkStep
{
    public WorkStepType WorkStepType { get; private set;}
}

如果您需要生成的域对象是特定类型,则只需将上面的 class 设为生成您要查找的类型的简单工厂即可。

public class WorkStepFactory
    {
        public WorkStepType WorkStepType { get; private set;}

public T CreateWorkStep<T>() where T : WorkStepBase{...} 
    }