You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

DDD聚合设计中封装与业务规则的冲突及C#解决方案咨询

DDD中聚合实体属性修改的权限与业务逻辑平衡问题

在领域驱动设计(DDD)中设计聚合和实体时,应仅向使用者暴露聚合的公共属性与方法。但修改部分属性时需执行复杂业务逻辑,例如修改User聚合的Email属性时,需校验该邮箱未被其他用户注册,这涉及数据库查询。

将仓储(或仓储接口)嵌入聚合方法属于不良实践,会引入进程外依赖,因此需将该逻辑置于DomainService或AppService中。但这会导致属性需设为internal或public,存在被误修改、绕过服务中业务规则的风险:

public class User : IAggregateRoot
{
    public int Id { get; }
    public string Email { get; set; }

    private User(int id, string email)
    {
        Id = id;
        Email = email;
    }
}

public class UserService
{
    private IUserRepository repository;

    public UserService(IUserRepository repository)
    {
        this.repository = repository;
    }

    public async Task ChangeEmail(int userId, string email)
    {
        var exist = await repository.GetByEmailAsync(email);
        if (exist != null)
            throw new DomainException("Email is already in use");

        var user = await repository.GetByIdAsync(userId);
        user.Email = email;
        await repository.SaveAsync(user);
    }
}

理想状态是属性仅允许私有修改,外部仅能通过ChangeEmail方法访问:

public string Email { get; private set; }

若C#支持友元类,可让服务访问聚合或实体的私有属性与方法,即可解决该问题;若允许程序集循环引用(每个方块为独立项目),也可解决,但C#禁止循环依赖。

尝试使用嵌套类访问私有成员,但嵌套类无法同时关联聚合及所属实体(如Order聚合与OrderItem实体无法共用同一嵌套类)。虽可采用类似方案,但会导致项目数量及依赖关系激增,若支持循环依赖则可简化。

内容的提问来源于stack exchange,提问作者Alexandr Kubit

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 01:27:36