【问题标题】:Mongodb persist domain entity and protect invariantsMongodb 持久化域实体并保护不变量
【发布时间】:2014-08-10 23:05:12
【问题描述】:

我正在使用具有聚合根和子实体的域驱动设计。

聚合不变量通过聚合根 ConfigurableService 方法强制执行,链接到子实体的方法,其中包含 GroupsDependencies 的列表,用于映射组之间的要求。

一个不变的例子是ConfigurableService 仅当 SkuId 包含在列表中的某个组中时才允许建立依赖关系。

如果我去公开组或依赖项(因为 mongodb 需要持久性),那么可以绕过这个域逻辑 - 所以我认为可以使用调用实体方法的公共属性来扩展该类,如下所示DependenciesGroups 属性:

public class ConfigurableService
{
    List<Groups> groups = new List<Groups>();
    Dependencies dependencies = new Dependencies();

    public void AddDependency(SkuId on, SkuId requires)
    {
        if(IsContainsSku(on) && IsContainsSku(requires))
            this.dependencies.SetRequiresFor(on, requires);
        else
            throw new Exception("SkuId doesnt exist");
    }

    public bool IsContainsSku(SkuId sku)
    {
        foreach(var group in groups)
        {
            if(group.ContainsSku(sku)==true)
            {
                return true;
            }
        }

        return false;
    }

    // other code snipped for breverity

    IEnumerable<Dependency> Dependencies
    {
        get { return this.dependencies.GetAllDependencies(); }

        set
        {
            foreach(var dependency in value)
            {
                this.AddDependency(
                    new SkuId(dependency.Source),
                    new SkuId(dependency.Target)
                    );
            }
        }
    }

    IEnumerable<Group> Groups
    {
        get { return this.groups; }

        set
        {
            this.groups.Clear();

            foreach(var group in groups)
            {
                this.groups.Add(group);
            }
        }
    }
}

我会重复每个需要持久化的内部属性,因为这将检查域逻辑。

这在构建对象时从存储库读取期间可以正常工作,只要按正确的顺序设置属性...例如,如果在 Dependencies 之前设置了组,我们最终会抛出异常(SkuID不存在)。

问题

  1. 有哪些推荐的方法来保护不变量并允许 Mongodb 持久化/检索域实体对象?

  2. mongodb 水合物时我可以控制属性设置的顺序吗 来自它的数据库?

  3. 或者我最好创建一个自定义序列化方法(如何 我会这样做)吗?

【问题讨论】:

    标签: c# mongodb architecture domain-driven-design domain-object


    【解决方案1】:

    我的同事想出了一个自定义序列化程序来解决这个问题,实体可以从 BsonSerializer DTO 手动重建:

    public class ConfigurableServicePersistenceMapper
    {
        public ConfigurableServiceId Id { get; set; }
        public string Description { get; set; }
        public HashSet<Group> Groups { get; set; }
        public Dependencies Dependencies { get; set; }
    }
    
    public class ConfigurableServiceSerializer : BsonBaseSerializer
    {
        public override void Serialize(BsonWriter bsonWriter, Type nominalType, object value, IBsonSerializationOptions options)
        {
            // implement using bsonWriter
            if (nominalType != typeof(ConfigurableService))
                throw new Exception("Object should be of type 'ConfigurableService'");
    
            var obj = (ConfigurableService)value;
    
            var map = new ConfigurableServicePersistenceMapper()
            {
                Dependencies = obj.Dependencies,
                Description = obj.Description,
                Groups = obj.Groups,
                Id = obj.Id
            };
    
            BsonSerializer.Serialize(bsonWriter, map);
        }
    
        public override object Deserialize(BsonReader bsonReader, Type nominalType, Type actualType, IBsonSerializationOptions options)
        {
            // implement using bsonreader
            if (nominalType != typeof(ConfigurableService))
                throw new Exception("object should be of type 'ConfigurableService'");
    
            var bson = BsonSerializer.Deserialize<BsonDocument>(bsonReader);
            var configurableServiceMapper = BsonSerializer.Deserialize<ConfigurableServicePersistenceMapper>(bson);
    
            var configurableService = new ConfigurableService(configurableServiceMapper.Id)
            {
                Description = configurableServiceMapper.Description
            };
    
    
            foreach (var group in configurableServiceMapper.Groups)
            {
                configurableService.NewGroup(group.Id);
                var retrievedGroup = configurableService.GetGroup(group.Id);
    
                retrievedGroup.Description = group.Description;
    
                foreach (var sku in group.Skus)
                {
                    retrievedGroup.Add(sku);
                }
    
                // set requirements
                List<Group> groupList = new List<Group>(configurableServiceMapper.Groups);
    
                foreach (var sku in group.Skus)
                {
                    List<string> dependencies =
                        new List<string>(configurableServiceMapper.Dependencies.GetDependenciesFor(sku));
    
    
                    foreach (var dependencySkuString in dependencies)
                    {
                        retrievedGroup.SetRequirementFor(sku)
                            .Requires(new SkuId(dependencySkuString));
                    }
                }
            }
            return configurableService;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2015-04-08
      • 1970-01-01
      • 2014-11-27
      • 2020-05-18
      • 2016-05-12
      • 1970-01-01
      • 1970-01-01
      • 2011-08-04
      • 2021-05-19
      相关资源
      最近更新 更多