设置域实体的身份 [英] Setting the identity of a Domain Entity

查看:107
本文介绍了设置域实体的身份的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

域中的所有实体都需要具有身份。通过从 DomainEntity 继承,我可以为课程提供身份。

All entities in the domain need to have identity. By inheriting from DomainEntity, I am able to provide identity to classes.

城市域实体(轻松阅读):

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

When a new entity is first created, an identity does not exist. Identity will only exist once the entity is persisted. Because of this, when creating a new instance of the entity, Id does not need to be supplied:

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

当使用 CityRepository ,那么第二个构造函数将被用于填充身份属性:

When cities are read from persistence using a CityRepository, then the second constructor will be used so to populate the identity property as well:

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 值。什么阻止别人这样做:

The problem I am having here is that I provide a constructor which can take in identity. This opens up a hole. I only want identity to be set in the repository layer, but client code could now also start setting Id values. What's stopping someone from doing this:

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

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

注意:我知道这不是DDD的完美实现,从一开始就有身份。 Guid 类型将有助于我解决这个问题,但我不幸没有这样的奢侈。

Note: I understand that this is not a perfect implementation of DDD as entities should have identity from the beginning. The Guid type would help me solve this problem, but I don't have that luxury unfortunately.

推荐答案

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

In addition to Ilya Palkin's answer I want to post another solution which is simpler but a bit tricky:


  1. 使 DomainEntity.UniqueId 受保护,因此可以从其子节点访问

  2. 引入工厂(或静态工厂方法)并定义它在City类中,所以它可以访问 DomainEntity.UniqueId 保护字段。

  1. Make DomainEntity.UniqueId protected, so it can be accessed from its childs
  2. Introduce a factory (or static factory method) and define it inside City class, so it can access the DomainEntity.UniqueId protected field.

优点:没有反射,代码是可测试的。

缺点:域层知道DAL层。

Pros: No reflection, code is testable.
Cons: Domain layer knows about DAL layer. A little bit tricky definition of the factory.

代码:

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);
    }
}

这篇关于设置域实体的身份的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆