gpt4 book ai didi

c# - 设置领域实体的身份

转载 作者:行者123 更新时间:2023-11-30 15:30:54 27 4
gpt4 key购买 nike

域中的所有实体都需要有身份。通过从 DomainEntity 继承,我能够为类提供标识。

城市域实体(为了便于阅读而进行了精简):

public class City : DomainEntity, IAggregateRoot
{
public string Name { get; private set; }

public Coordinate Coordinate { get; private set; }

public City(string name, decimal latitude, decimal longitude)
{
Name = name;
SetLocation(latitude, longitude);
}

public City(string name, decimal latitude, decimal longitude, int id)
: base(id)
{
Name = name;
Coordinate = coordinate;
SetLocation(latitude, longitude);
}

public void SetLocation(decimal latitude, decimal longitude)
{
Coordinate = new Coordinate(latitude, longitude);
}
}

DomainEntity 抽象类:

public abstract class DomainEntity
{
private int? uniqueId;

public int Id
{
get
{
return uniqueId.Value;
}
}

public DomainEntity()
{ }

public DomainEntity(int id)
{
uniqueId = id;
}
}

首次创建新实体时,身份不存在。身份只有在实体被持久化后才会存在。因此,在创建实体的新实例时,不需要提供 Id:

var city = new City("Cape Town", 18.42, -33.92);

当使用 CityRepository 从持久化中读取城市时,将使用第二个构造函数来填充标识属性:

public class CityRepository : ICityRepository
{
public City Find(int id)
{
var cityTblEntity = context.Set<CityTbl>().Find(id);

return new City(cityTblEntity.Name, cityTblEntity.Lat, cityTblEntity.Long, cityTblEntity.Id);
}
}

我在这里遇到的问题是我提供了一个可以接受身份的构造函数。这会打开一个洞。我只想在存储库层设置身份,但客户端代码现在也可以开始设置 Id 值。是什么阻止了某人这样做:

var city = new City("Cape Town", 18.42, -33.92, 99999);  // What is 99999? It could even be an existing entity!

我如何提供方法来在我的存储库中设置实体身份,但对客户端代码隐藏它?也许我的设计有缺陷。我可以使用工厂来解决这个问题吗?

注意:我知道这不是 DDD 的完美实现,因为实体从一开始就应该具有身份。 Guid 类型可以帮助我解决这个问题,但不幸的是我没有那么奢侈。

最佳答案

除了 Ilya Palkin 的回答之外,我还想发布另一个更简单但有点棘手的解决方案:

  1. 使 DomainEntity.UniqueId 受到保护,以便可以从其子级访问它
  2. 引入工厂(或静态工厂方法)并将其定义在 City 类中,因此它可以访问 DomainEntity.UniqueId protected 字段。

优点:没有反射,代码是可测试的。
缺点:域层了解 DAL 层。工厂的定义有点棘手。

代码:

public abstract class DomainEntity
{
// Set UniqueId to protected, so you can access it from childs
protected int? UniqueId;
}

public class City : DomainEntity
{
public string Name { get; private set; }

public City(string name)
{
Name = name;
}

// Introduce a factory that creates a domain entity from a table entity
// make it internal, so you can access only from defined assemblies
// also if you don't like static you can introduce a factory class here
// just put it inside City class definition
internal static City CreateFrom(CityTbl cityTbl)
{
var city = new City(cityTbl.Name); // or use auto mapping
// set the id field here
city.UniqueId = cityTbl.Id;
return city;
}
}

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

static void Main()
{
var city = new City("Minsk");

// can't access UniqueId and factory from a different assembly
// city.UniqueId = 1;
// City.CreateFrom(new CityTbl());
}

// Your repository will look like
// and it won't know about how to create a domain entity which is good in terms of SRP
// You can inject the factory through constructor if you don't like statics
// just put it inside City class
public class CityRepository : ICityRepository
{
public City Find(int id)
{
var cityTblEntity = context.Set<CityTbl>().Find(id);

return City.CreateFrom(cityTblEntity);
}
}

关于c# - 设置领域实体的身份,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21452984/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com