• abp学习日志三(实体&聚合根)


    实体

    实体是DDD(Domain Driven Design)中核心概念.Eric Evans是这样描述实体的 “一个没有从其属性,而是通过连续性和身份的线索来定义的对象”

    实体通常映射到关系型数据库的表中。1

    Product实体

    按照项目结构,Product应该创建在Domain项目中,所以源码是这样的
    目录结构
    在这里插入图片描述
    代码

    using System;
    using System.Collections.Generic;
    using System.Text;
    using Volo.Abp.Domain.Entities;
    
    namespace LY.Shop.Models
    {
        public class Product :Entity<Guid> // AggregateRoot<Guid>
        {
            public string ProductName { get; set; }
            public string ProductUnit { get; set; }
            public string ProductDescription { get; set; }
            public decimal ProductPrice { get; set; }
            public decimal StoreNumbers { get; set; } 
            public string Note { get; set; }
    
            protected Product()
            {
            }
            public Product(Guid id)
             : base(id)
            {
            }
        }
    }
    
    

    Entity类

    这个类是abp框架提供的,看一下他的源码

    using System;
    using System.Collections.Generic;
    using System.Reflection;
    using Volo.Abp.MultiTenancy;
    
    namespace Volo.Abp.Domain.Entities
    {
        /// <inheritdoc/>
        [Serializable]
        public abstract class Entity : IEntity
        {
            /// <inheritdoc/>
            public override string ToString()
            {
                return $"[ENTITY: {GetType().Name}] Keys = {GetKeys().JoinAsString(", ")}";
            }
    
            public abstract object[] GetKeys();
        }
    
        /// <inheritdoc cref="IEntity{TKey}" />
        [Serializable]
        public abstract class Entity<TKey> : Entity, IEntity<TKey>
        {
            /// <inheritdoc/>
            public virtual TKey Id { get; protected set; }
    
            protected Entity()
            {
    
            }
    
            protected Entity(TKey id)
            {
                Id = id;
            }
    
            public bool EntityEquals(object obj)
            {
                if (obj == null || !(obj is Entity<TKey>))
                {
                    return false;
                }
    
                //Same instances must be considered as equal
                if (ReferenceEquals(this, obj))
                {
                    return true;
                }
    
                //Transient objects are not considered as equal
                var other = (Entity<TKey>)obj;
                if (EntityHelper.HasDefaultId(this) && EntityHelper.HasDefaultId(other))
                {
                    return false;
                }
    
                //Must have a IS-A relation of types or must be same type
                var typeOfThis = GetType().GetTypeInfo();
                var typeOfOther = other.GetType().GetTypeInfo();
                if (!typeOfThis.IsAssignableFrom(typeOfOther) && !typeOfOther.IsAssignableFrom(typeOfThis))
                {
                    return false;
                }
    
                //Different tenants may have an entity with same Id.
                if (this is IMultiTenant && other is IMultiTenant &&
                    this.As<IMultiTenant>().TenantId != other.As<IMultiTenant>().TenantId)
                {
                    return false;
                }
    
                return Id.Equals(other.Id);
            }
            
            public override object[] GetKeys()
            {
                return new object[] {Id};
            }
    
            /// <inheritdoc/>
            public override string ToString()
            {
                return $"[ENTITY: {GetType().Name}] Id = {Id}";
            }
        }
    }
    
    

    这份源码没有什么好分析的,就是做了一个基类,重写了几个常用的方法。

    聚合根

    “聚合是域驱动设计中的一种模式.DDD的聚合是一组可以作为一个单元处理的域对象.例如,订单及订单系列的商品,这些是独立的对象,但将订单(连同订单系列的商品)视为一个聚合通常是很有用的”2

    源码

    namespace Volo.Abp.Domain.Entities
    {
        /// <summary>
        /// Defines an aggregate root. It's primary key may not be "Id" or it may have a composite primary key.
        /// Use <see cref="IAggregateRoot{TKey}"/> where possible for better integration to repositories and other structures in the framework.
        /// </summary>
        public interface IAggregateRoot : IEntity
        {
    
        }
    
        /// <summary>
        /// Defines an aggregate root with a single primary key with "Id" property.
        /// </summary>
        /// <typeparam name="TKey">Type of the primary key of the entity</typeparam>
        public interface IAggregateRoot<TKey> : IEntity<TKey>, IAggregateRoot
        {
    
        }
    }
    
    
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using Volo.Abp.Auditing;
    using Volo.Abp.Data;
    
    namespace Volo.Abp.Domain.Entities
    {
        [Serializable]
        public abstract class AggregateRoot : Entity, 
            IAggregateRoot,
            IGeneratesDomainEvents, 
            IHasExtraProperties,
            IHasConcurrencyStamp
        {
            public virtual Dictionary<string, object> ExtraProperties { get; protected set; }
    
            [DisableAuditing]
            public virtual string ConcurrencyStamp { get; set; }
    
            private readonly ICollection<object> _localEvents = new Collection<object>();
            private readonly ICollection<object> _distributedEvents = new Collection<object>();
    
            protected AggregateRoot()
            {
                ExtraProperties = new Dictionary<string, object>();
                ConcurrencyStamp = Guid.NewGuid().ToString("N");
            }
    
            protected virtual void AddLocalEvent(object eventData)
            {
                _localEvents.Add(eventData);
            }
    
            protected virtual void AddDistributedEvent(object eventData)
            {
                _distributedEvents.Add(eventData);
            }
    
            public virtual IEnumerable<object> GetLocalEvents()
            {
                return _localEvents;
            }
    
            public virtual IEnumerable<object> GetDistributedEvents()
            {
                return _distributedEvents;
            }
    
            public virtual void ClearLocalEvents()
            {
                _localEvents.Clear();
            }
    
            public virtual void ClearDistributedEvents()
            {
                _distributedEvents.Clear();
            }
        }
    
        [Serializable]
        public abstract class AggregateRoot<TKey> : Entity<TKey>, 
            IAggregateRoot<TKey>, 
            IGeneratesDomainEvents, 
            IHasExtraProperties,
            IHasConcurrencyStamp
        {
            public virtual Dictionary<string, object> ExtraProperties { get; protected set; }
    
            [DisableAuditing]
            public virtual string ConcurrencyStamp { get; set; }
    
            private readonly ICollection<object> _localEvents = new Collection<object>();
            private readonly ICollection<object> _distributedEvents = new Collection<object>();
    
            protected AggregateRoot()
            {
                ExtraProperties = new Dictionary<string, object>();
                ConcurrencyStamp = Guid.NewGuid().ToString("N");
            }
    
            protected AggregateRoot(TKey id)
                : base(id)
            {
                ExtraProperties = new Dictionary<string, object>();
                ConcurrencyStamp = Guid.NewGuid().ToString("N");
            }
    
            protected virtual void AddLocalEvent(object eventData)
            {
                _localEvents.Add(eventData);
            }
    
            protected virtual void AddDistributedEvent(object eventData)
            {
                _distributedEvents.Add(eventData);
            }
    
            public virtual IEnumerable<object> GetLocalEvents()
            {
                return _localEvents;
            }
    
            public virtual IEnumerable<object> GetDistributedEvents()
            {
                return _distributedEvents;
            }
    
            public virtual void ClearLocalEvents()
            {
                _localEvents.Clear();
            }
    
            public virtual void ClearDistributedEvents()
            {
                _distributedEvents.Clear();
            }
        }
    }
    

    聚合根中除了继承IEntity接口外,还继承了其他几个接口(稍后再说),主要思想还是对IEntity再一次封装。

    官方框架已经给出了几种聚合根,扩展了不同的常用字段

    • CreationAuditedEntity 和 CreationAuditedAggregateRoot 实现了 ICreationAuditedObject 接口.
    • AuditedEntity 和 AuditedAggregateRoot 实现了 IAuditedObject 接口.
    • FullAuditedEntity and FullAuditedAggregateRoot 实现了 IFullAuditedObject 接口.

    额外属性

    关于额外属性使用到的情况非常少,大致就是通过json存在数据库中,映射到实体的ExtraProperties 属性,通过GetProperty 和 SetProperty方法进行取值和写值,可以通过HasProperty 判断是否存在该属性,也可以通过RemoveProperty 方法删除扩展属性中的某一个属性。


    1. 官网原话,值得推敲,Eric Evans的原话咱没看懂,但是 下面语句映射到关系数据库表中就清晰了许多。 ↩︎

    2. 聚合根其实就是对实体的进一步封装。继承自IEntity接口 ↩︎

  • 相关阅读:
    ubuntu一般软件安装在什么目录
    Swing是一把刀
    eclipse 3.6的VE配置 Visual Editor for eclipse3.6
    有关import sun.audio.AudioPlayer(或者其它文件)的问题
    ubuntu 下安装jdk
    linux查看java jdk安装路径
    关于绿色
    Swing如何正确的处理界面中的线程(EDT)
    在Eclipse4.2x中安装最新版插件WindowBuilder
    Eclipse java swing开发环境
  • 原文地址:https://www.cnblogs.com/xiaoch/p/13417916.html
Copyright © 2020-2023  润新知