【三】Asp.NetCore使用Efcore+Mysql实现CodeFirst@Asp.netcore Code First +DDD学习笔记

4 篇文章 1 订阅
4 篇文章 0 订阅

Asp.NetCore使用Efcore+Mysql实现CodeFirst,并且自动生成EfCore的builderModel的实现过程

主题:Asp.netcore Code First +DDD学习笔记

目录:

   【一】 CodeFirst+DDD项目结构的构建

   【二】Asp.Netcore使用Panda.DynamicWebApi来进行Controller解耦

   【三】Asp.NetCore使用Efcore+Mysql实现CodeFirst

   【四】EfCore实现全自动化迁移

     案例代码下载点击

Domain和数据持久化的实现,Domain和Controller之间的链接本来就是可隔离的,所以直接分开就可以了,通过orm进行对数据的控制和持久化,这里采用Efcore+mysql实现codefirst来进行实现。

Domain和Efcore之间我们也不能过度耦合,所以这里不采用传统的手写efcontent,这里采用特性和反射来实现自动生成efcontent,链接数据库采用的是Asp mvc依赖注入。

Domain和Dto之间的映射。

1、EfModel特性的实现

      在EfCoreRepository项目下添加一个文件夹命名为EfModelAttributes和一个类命名为EfEntityBuilder类、在EfModelAttributes该文件夹下添加一个类命名为EfModelAttribute,如下图:

EfModelAttribute代码的实现

using System;

namespace EfCoreRepository.EfModelAttributes
{
    /// <summary>
    /// EFmodel的实体特性
    /// 作者:猴子 2019-09-19
    /// </summary>
    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
    public class EfModelAttribute: Attribute
    {
    }
}

EfEntityBuilder代码的实现

using Microsoft.EntityFrameworkCore;
using System;
using System.Linq;
using System.Reflection;

namespace EfCoreRepository
{
    /// <summary>
    /// ef实体的创建
    /// </summary>
    public static class EfEntityBuilder
    {
        /// <summary>
        /// 从程序反射添加实体配置
        /// </summary>
        /// <typeparam name="TAttribute"></typeparam>
        /// <param name="modelBuilder"></param>
        /// <param name="assembly"></param>
        public static void AddEntityConfigurationsFromAssembly<TAttribute>(this ModelBuilder modelBuilder, Assembly assembly)
            where TAttribute : Attribute
        {
            var autoTypes = assembly.GetTypes().Where(x => x.GetCustomAttribute<TAttribute>() != null && x.IsPublic);
            foreach (var entity in autoTypes)
            {
                modelBuilder.Model.AddEntityType(entity);
            }
            foreach (var entity in modelBuilder.Model.GetEntityTypes())
            {
                var currentTableName = modelBuilder.Entity(entity.Name).Metadata.Relational().TableName;
                modelBuilder.Entity(entity.Name).ToTable(currentTableName.ToLower());
                var properties = entity.GetProperties();
                foreach (var property in properties)
                    modelBuilder.Entity(entity.Name).Property(property.Name).HasColumnName(property.Name.ToLower());
            }
        }
    }
}

2、Domain里面的Efcontent的实现

     在Domain这个项目里面添加三个文件夹分别命名为:CoreEntity(存放实体基类的),Domains(存放实体的),EfCoreContent(存放efcorecontent的)。在EfCoreContent下添加一个EfContent类,如下图:

     

EfContent的代码实现:

using EfCoreRepository;
using EfCoreRepository.EfModelAttributes;
using Microsoft.EntityFrameworkCore;
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

namespace Domain.EfCoreContent
{
    public class EfContent : DbContext
    {
        public EfContent(DbContextOptions<EfContent> options) : base(options)
        {
            //部署时需要创建一个数据库实体版本管理表
            //每次需要执行创建迁移命令Add-Migration InitialCreate
            //执行前需要创建该表

            //CREATE TABLE `__EFMigrationsHistory` 
            //(
            //    `MigrationId` nvarchar(150) NOT NULL,
            //    `ProductVersion` nvarchar(32) NOT NULL,
            //     PRIMARY KEY(`MigrationId`)
            //);

            if (base.Database.GetPendingMigrations().Any())
            {
                base.Database.Migrate(); //执行迁移
            } 
        }

        / <summary>
        / 因为使用无参构造器,所以需要自带链接字符串
        / </summary>
        / <param name="optionsBuilder"></param>
        //protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        //{
        //    if (!optionsBuilder.IsConfigured)
        //        optionsBuilder.UseMySQL("Database = 'studyddd'; Data Source = 'localhost'; User Id = 'root'; Password = ''; charset = 'utf8'; pooling = true; Allow Zero Datetime = True;Allow User Variables=True;TreatTinyAsBoolean=false");
        //} 

        /// <summary>
        /// 创建实体
        /// </summary>
        /// <param name="modelBuilder"></param>
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.AddEntityConfigurationsFromAssembly<EfModelAttribute>(Assembly.GetExecutingAssembly());
            base.OnModelCreating(modelBuilder);
        }

        /// <summary>
        /// 扩展查询
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public IQueryable<T> Where<T>(Expression<Func<T, bool>> predicate) where T : class
        {
            return base.Set<T>().Where(predicate);
        }
    }
}

  3、在Api项目里面注入Efcontent

        在Api的Startup文件里面的ConfigureServices方法添加如下代码

services.AddDbContextPool<EfContent>(options =>
                options.UseMySQL("Database = 'studyddd'; Data Source = 'localhost'; User Id = 'root'; Password = ''; charset = 'utf8'; pooling = true; Allow Zero Datetime = True;Allow User Variables=True;TreatTinyAsBoolean=false",b=>b.MigrationsAssembly("Api")), 200);

 这时候,自动生成Efcontent已经完成。

4、创建一个实体进行测试

 在Domain项目下的Domains文件夹里面创建Tests文件夹,在该文件夹下创建Test类如下

Test代码实现如下:

using EfCoreRepository.EfModelAttributes;
using System.ComponentModel.DataAnnotations;

namespace Domain.Domains.Tests
{
    /// <summary>
    /// 测试类
    /// </summary>
    [EfModel]
    public class Test 
    {
        [Key]
        public int Id { get; set; }
        public string HelloWorld { get; set; }
    }
}

注:这里的实体要打上刚刚我们做的EfModel特性,不打特性的不会被自动创建到Efcontent里面。

5、在Controller里面开始使用Test该实体进行数据存储和访问。

      修改Controller项目里面的TestAppService这个类里面如下

using Controller.Core;
using Domain.EfCoreContent;
using System.Linq;

namespace Controller.Controllers.Test
{
    /// <summary>
    /// 测试类
    /// </summary>
    public class TestAppService : AppService, IAppService
    {
        public EfContent EfContent { get; set; }
        public TestAppService(EfContent efContent)
        {
            EfContent = efContent;
        }


        public string GetHelloWorld()
        {
            return "Hello World !!";
        }

        /// <summary>
        /// 添加一条测试数据
        /// </summary>
        /// <returns></returns>
        public string AddTest()
        {
            Domain.Domains.Tests.Test test = new Domain.Domains.Tests.Test();
            test.HelloWorld="你好世界";
            EfContent.Add(test);
            EfContent.SaveChanges();
            return "写入成功";
        }

        /// <summary>
        /// 获取一条数据
        /// </summary>
        /// <returns></returns>
        public Domain.Domains.Tests.Test GetTest()
        {
            return EfContent.Where<Domain.Domains.Tests.Test>(p => p.HelloWorld == "你好世界").FirstOrDefault(); ;
        }
    }
}

我实现了一个添加数据的接口,和一个查询数据的接口。

当然这时候我们还不能之间运行项目开始测试,这时候我们需要到数据库创建一个数据库版本管理表,运行如下sql

CREATE TABLE `__EFMigrationsHistory` 
(
  `MigrationId` nvarchar(150) NOT NULL,
  `ProductVersion` nvarchar(32) NOT NULL,
   PRIMARY KEY(`MigrationId`)
);

生成表后如图:

 

之后如果我们实体进行了修改或者调整,需要在【程序包管理控制台里面执行迁移命令】,每次修改或者添加都需要执行创建迁移命令

 Add-Migration InitialCreate

注:程序包管理器执行命令时,要选择Api项目,如图

如何打开程序包管理控制台

  

执行命令成功后,你会发现在Api项目里面多了一个文件夹,如图:

该文件夹里面的内容不用管他,开始启动项目Api项目,打开swagger你会发现多了两个接口和一个Models,如下图

 

执行一次添加一条测试数据的接口,你会发现数据库里面自动多了一个test表,如下图

数据库:

执行下 查询接口:

到这里EfCore+Mysql  CodeFirst方式已经实现。

6、Dto的使用:

     Dto主要作用是控制返回和接入的数据,所以他和别的模块并没有一些很强的交合,主要就是一些实体。我们在Dto里面创建一个testdto如下图

TestDto的代码实现如下

namespace Dto.TestDtos
{
    public class TestDto
    {
        public string HelloWorld { get; set; } 

    }
}

在Controller里面的使用,修改获取一条数据的接口如下:

        /// <summary>
        /// 获取一条数据
        /// </summary>
        /// <returns></returns>
        public Dto.TestDtos.TestDto GetTest()
        {
            return EntityToDto<Dto.TestDtos.TestDto>(EfContent.Where<Domain.Domains.Tests.Test>(p => p.HelloWorld == "你好世界").FirstOrDefault()); 
        }

这里使用之前在基类里面封装的一个实体到Dto的方法。

再次运行Api项目,使用Swagger执行 获取一条数据的接口会发现返回的数据Id消失了,如下:

 

总结:这里我发现该CodeFirst方式,有个美中不足的就是结构迁移,需要执行一下迁移命令,还不能全部代码化,后续需要进行优化,如果有大神有建议和方法,请大神不吝赐教。

github地址:https://github.com/houliren/Asp.netcore-Code-First-DDD

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值