zoukankan      html  css  js  c++  java
  • 基于ABP VNext及CodeFirst,迈开走向DDD的第一步

       前言: DDD的基础知识这里就不讲了,网上有很多,无外乎 架构从以外的三层变成四层,有聚合、实体、值对象、领域服务等这些概念,我也是最近看了很多,但无从下手,正好我们现有的项目是基于ABP

    框架的,虽说也支持DDD,也是分为了4个项目,有领域有Domain,但感觉还是个三层项目,想了想,最大的问题还是收到新的任务后,总是从数据库开始,然后T4生成实体,没有太多的去进行领域划分。所以本次

    我们使用EFCore的CodeFirst和ABPVnext来体验一下怎么在项目中真正的运用DDD。

    --------------------------------------------------------------------------------------------------------------------------------------------------

      新建项目

      

      我这里使用ABP的CLI命令创建的,当然也可以直接在网站(https://www.abp.io/get-started)上下载

      我这里由于没有装mssql,所以切换到了mysql,具体可参考https://docs.abp.io/zh-Hans/abp/latest/Entity-Framework-Core-MySQL

    切换后,我们使用下面这俩命令创建一下数据库

    Add-Migration "Init"
    Update-DataBase

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    重点来了

      接下来我们正式从一个订单的领域开始, 首先看一张图

     

    首先我们先创建个地址的值对象 

      /// <summary>
        /// 地址(值对象)
        /// </summary>
        public class Address : ValueObject
        {
            public String Street { get; private set; }
            public String City { get; private set; }
            public String State { get; private set; }
            public String Country { get; private set; }
            public String ZipCode { get; private set; }
    
            public Address() { }
    
            public Address(string street, string city, string state, string country, string zipcode)
            {
                Street = street;
                City = city;
                State = state;
                Country = country;
                ZipCode = zipcode;
            }
    
            protected override IEnumerable<object> GetAtomicValues()
            {
                // Using a yield return statement to return each element one at a time
                yield return Street;
                yield return City;
                yield return State;
                yield return Country;
                yield return ZipCode;
            }
        }

    创建实体

     /// <summary>
        /// 订单明细实体
        /// </summary>
        public class OrderItem : Entity
        {
            public virtual Guid OrderId { get; protected set; }
    
            public virtual Guid ProductId { get; protected set; }
    
            public virtual int Count { get; protected set; }
    
            protected OrderItem()
            {
    
            }
    
            internal OrderItem(Guid orderId, Guid productId, int count)
            {
                OrderId = orderId;
                ProductId = productId;
                Count = count;
            }
    
            internal void ChangeCount(int newCount)
            {
                Count = newCount;
            }
    
            public override object[] GetKeys()
            {
                return new Object[] { OrderId, ProductId };
            }
        }

    创建订单聚合根

     /// <summary>
        /// 订单聚合根
        /// </summary>
        public class Order : AggregateRoot<Guid>
        {
            public virtual string ReferenceNo { get; protected set; }
    
            public virtual int TotalItemCount { get; protected set; }
    
            public virtual DateTime CreationTime { get; protected set; }
    
            public virtual List<OrderItem> OrderLines { get; protected set; }
    
            public Address Address { get; protected set; }//值对象
    
            public string UserName { get; protected set; }
    
            protected Order()
            {
    
            }
    
            public Order(Guid id, string referenceNo, string userName, Address address)
            {
                Check.NotNull(referenceNo, nameof(referenceNo));
    
                Id = id;
                ReferenceNo = referenceNo;
                Address = address;
                OrderLines = new List<OrderItem>();
                CreationTime = DateTime.Now;
                UserName = userName;
            }
    
            public void AddProduct(Guid productId, int count)
            {
                if (count <= 0)
                {
                    throw new ArgumentException(
                        "You can not add zero or negative count of products!",
                        nameof(count)
                    );
                }
    
                var existingLine = OrderLines.FirstOrDefault(ol => ol.ProductId == productId);
    
                if (existingLine == null)
                {
                    OrderLines.Add(new OrderItem(this.Id, productId, count));
                }
                else
                {
                    existingLine.ChangeCount(existingLine.Count + count);
                }
    
                TotalItemCount += count;
            }
        }

    然后在Context中添加

    public DbSet<Order> Orders { get; set; }
    
    public DbSet<OrderItem> OrderItems { get; set; }
    public static void ConfigureDDDTest(this ModelBuilder builder)
            {
                Check.NotNull(builder, nameof(builder));
    
                /* Configure your own tables/entities inside here */
    
                //builder.Entity<YourEntity>(b =>
                //{
                //    b.ToTable(DDDTestConsts.DbTablePrefix + "YourEntities", DDDTestConsts.DbSchema);
    
                //    //...
                //});
    
                builder.Entity<Order>(b =>
                {
                    b.ToTable(DDDTestConsts.DbTablePrefix + "Orders", DDDTestConsts.DbSchema);
                    b.ConfigureByConvention();
                    b.OwnsOne(o => o.Address, a => {
                        a.WithOwner();
                    });
                    //b.Property(x => x.Name).IsRequired().HasMaxLength(128);
                });
    
                builder.Entity<OrderItem>(b =>
                {
                    b.ToTable(DDDTestConsts.DbTablePrefix + "OrderLines", DDDTestConsts.DbSchema);
                    b.ConfigureByConvention();
                    b.HasKey(x => new { x.OrderId, x.ProductId });
                    //b.Property(x => x.Name).IsRequired().HasMaxLength(128);
                });
            }

    此时我们再执行迁移命令,会发现数据库中多了俩张表,值对象在聚合中

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    这时候我们执行个创建的方法是,会出现这个错误

    这个时候只需要把 base.OnModelCreating(builder);,移到builder.ConfigureDDDTest();下面即可

    自定义仓储的话,我们需要把接口定义在领域层,把实现放在基础设施层

     public class OrderRepository : EfCoreRepository<DDDTestDbContext, Order, Guid>, IOrderRepository
        {
            public OrderRepository(IDbContextProvider<DDDTestDbContext> dbContextProvider)
         : base(dbContextProvider)
            {
    
            }
    
            public async Task<Order> Get(Guid orderId)
            {
    
                var order = await DbContext
                                   .Orders
                                   .Include(x => x.Address)
                                   .FirstOrDefaultAsync(o => o.Id == orderId);
                if (order == null)
                {
                    order = DbContext
                                .Orders
                                .Local
                                .FirstOrDefault(o => o.Id == orderId);
                }
                if (order != null)
                {
                    await DbContext.Entry(order)
                        .Collection(i => i.OrderLines).LoadAsync();
                }
    
                return order;
            }
        }

     

     整体实现下来,不知道有没有点对DDD的感觉呢?

    参考:  

    https://www.cnblogs.com/richieyang/p/5373250.html
    https://cn.abp.io/blog/Abp/Abp-vNext-Announcement
    https://docs.abp.io/en/abp/latest/
    https://github.com/abpframework/abp/issues/2640
    https://docs.microsoft.com/zh-cn/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/microservice-domain-model
    https://github.com/dotnet-architecture/eShopOnContainers
  • 相关阅读:
    ajax简单案例
    jquery中的数据传输
    java-Reflect
    Factory Method 和AbstractFactory
    Singleton
    英语六级口语备考指南
    ACM信息汇总
    jquery练习
    char可不可以存汉字
    信息安全
  • 原文地址:https://www.cnblogs.com/mchuang/p/12504150.html
Copyright © 2011-2022 走看看