是否可以在域模型上创建不可变的 属性?
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{...}
}
我们有许多逻辑域对象都驻留在同一个物理数据库中 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{...}
}