.NET Core、EF、Dapper、MySQL 多种方式实现数据库操作(动态注册实体类)

目录

前言

最近在学习、研究 .NET Core 方面的知识,动手搭建了一些小的 Demo,对 .NET Core 有了初步的认识了解。

恰逢公司的项目需要,有一个需求,不大不小可以作为转 .NET Core 的示例项目来做。

这个项目的搭建工作由我来做,我这边做了一些技术预研,对呀用到的技术进行预研,其中包括:Kafka、SignalR、Topshelf。

但是在做单数据库的时候出现了一些问题。

一、技术选型

这里说的技术选型是数据操作这一块的。

我们之所以选择了 EF、Dapper 结合,是有原因的。以前是直接用的 EF DBFirst 直接拖库过来,用 Linq 语句查询,但是这样对于多张表的连表查询存在很大的隐患,因为这样生成的 SQL 语句不可靠,有时候生成的太复杂,效率太低,所以最终选择了 EF 和 Dapper 结合。对于简单的查询直接用 EF 操作,对于复杂一些的查询写 SQL 语句用 Dapper 查询。

这个选型是原先 .NET 下的,这次转的话,也按照这个来。

二、遇到的坑

在具体的实施中遇到了几个坑,下面就展开说说。

2.1、.NET Core 下 EF 的问题

.NET  Core 下的 EF 和原先平台的有挺大的差别,首先构造函数的差别:

.NET  下的

public DbContext(string nameOrConnectionString);

public DbContext(string nameOrConnectionString, DbCompiledModel model);

public DbContext(DbConnection existingConnection, bool contextOwnsConnection);

public DbContext(ObjectContext objectContext, bool dbContextOwnsObjectContext);

public DbContext(DbConnection existingConnection, DbCompiledModel model, bool contextOwnsConnection);

protected DbContext();

protected DbContext(DbCompiledModel model);

.NET Core 下的

public DbContext([NotNullAttribute] DbContextOptions options);

protected DbContext();

主要是因为 .NET Core 下功能模块的注册使用的新的方式。

那么在.NET Core 下继承 DbContext 并对其扩展如下:

public class DbContextTest : DbContext
    {
        public DbContextTest(DbContextOptions<DbContextTest> options)
            : base(options)
        {
        }
    }
public class MySQLDatabase
    {
        #region 构造函数
        /// <summary>
        /// 构造方法
        /// </summary>
        /// <param name="connString">连接串</param>
        public MySQlDatabase(string connString)
        {
            var optionBuilder = new DbContextOptionsBuilder<DatabaseContext>();

        optionBuilder.UseMySql(connString, mysqlOptions =>
        {
          mysqlOptions.ServerVersion(new Version(5, 7, 22), Pomelo.EntityFrameworkCore.MySql.Infrastructure.ServerType.MySql);
        });

            dbcontext = new DatabaseContext(optionBuilder.Options);
            Dapper.DefaultTypeMap.MatchNamesWithUnderscores = true;
        }

     // 这里是扩展的一些方法 }

2.2、数据库实体类的注册

因为选择了 EF 和 Dapper 那么需要自己动态建实体类并注册。

原先写了一个实体类生成的工具,这里拿来直接用了,在注册的时候 EF 和以前的注册方式有了改变,这里有对其扩展的代码:

namespace DataBase.Mapping
{
    public interface IEntityMappingConfiguration
    {
        void Map(ModelBuilder b);
    }

    public interface IEntityMappingConfiguration<T> : IEntityMappingConfiguration where T : class
    {
        void Map(EntityTypeBuilder<T> builder);
    }

    public abstract class EntityMappingConfiguration<T> : IEntityMappingConfiguration<T> where T : class
    {
        public abstract void Map(EntityTypeBuilder<T> b);

        public void Map(ModelBuilder b)
        {
            Map(b.Entity<T>());
        }
    }

    public static class ModelBuilderExtenions
    {
        private static IEnumerable<Type> GetMappingTypes(this Assembly assembly, Type mappingInterface)
        {
            return assembly.GetTypes().Where(x => !x.IsAbstract && x.GetInterfaces().Any(y => y.GetTypeInfo().IsGenericType && y.GetGenericTypeDefinition() == mappingInterface));
        }

        public static void AddEntityConfigurationsFromAssembly(this ModelBuilder modelBuilder, Assembly assembly)
        {
            var mappingTypes = assembly.GetMappingTypes(typeof(IEntityMappingConfiguration<>));
            IEnumerable<IEntityMappingConfiguration> configs = mappingTypes.Select(Activator.CreateInstance).Cast<IEntityMappingConfiguration>();
            foreach (var config in configs)
            {
                config.Map(modelBuilder);
            }
        }
    }
}

实体类的 Mapping,这个是继承了上面的接口 :

    public class ApplicationMap : EntityMappingConfiguration<ApplicationEntity>
    {
        public override void Map(EntityTypeBuilder<ApplicationEntity> b)
        {
            b.ToTable("application")
                .HasKey(p => p.Id);
        }
    }

那么在 DbContextTest 里面重写 OnModelCreating 方法:

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);

            string assembleFileName = Assembly.GetExecutingAssembly().CodeBase.Replace("DataBase.dll", "Mapping.dll").Replace("file:///", "");
            Assembly asm = Assembly.LoadFile(assembleFileName);
            modelBuilder.AddEntityConfigurationsFromAssembly(asm);
        }

这样代码工作基本完成了。

切记坑:

开始用的是 MySQL 官方的驱动:MySql.Data.EntityFrameworkCore ,但是一直报错:" The 'MySQLNumberTypeMapping' does not support value conversions. "

后来改用 Pomelo.EntityFrameworkCore.MySql 就可以了。

这个坑困扰了几天,真是憔悴了些。

原文地址:https://www.cnblogs.com/zhurong/p/9804790.html