zoukankan      html  css  js  c++  java
  • EF6&EFCore 注册/使用实体类的正确姿势

    首先回顾下EF中常规使用流程

    1.新建实体类以及实体配置(data nnotation或fluent api)

        [Table("Users")]
        public class Users
        {
            [Key]
            public Guid Id { get; set; }
    
            [StringLength(10)]
            public string Name { get; set; }
        }

    2.新建数据库上下文类MyDbContext

     1     public class MyDbContext : DbContext
     2     {
     3         public MyDbContext() { }
     4 
     5         public DbSet<Users> Users { get; set; }
     6 
     7         protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
     8         {
     9             optionsBuilder.UseSqlServer("connectionString");
    10         }
    11 
    12         protected override void OnModelCreating(ModelBuilder modelBuilder)
    13         {
    14             base.OnModelCreating(modelBuilder);
    15         }
    16     }

    3.开始欢乐的操作Users

                using (MyDbContext context = new MyDbContext())
                {
                    context.Users.FirstOrDefaultAsync(r => r.Name == "老王");
                }

    一切看起来都是很美好的,但假如有一天你面对上千个实体的时候,你可能会开始想用代码生成器.EF6中你还可以用modelBuilder.RegisterEntityType(type);那么现在又有一个新的要求,需要能同时使用data nnotation和fluent api进行实体配置.自动根据约定注册实体,自动注册fluent api配置类.EF中注册实体的本质就是注册DbSet,方法非常多.

    ok,直接贴代码,EF6:

           /// <summary>
            /// 注册某个程序集中所有<typeparamref name="TEntityBase"/>的非抽象实体子类
            /// </summary>
            /// <typeparam name="TEntityBase">实体基类</typeparam>
            /// <param name="modelBuilder"></param>
            /// <param name="assembly">注册程序集</param>
            public static void RegisterEntitiesFromAssembly<TEntityBase>(this DbModelBuilder modelBuilder, Assembly assembly)
                where TEntityBase : class
            {
                modelBuilder.RegisterEntitiesFromAssembly(assembly, r => !r.IsAbstract && r.IsClass && r.IsChildTypeOf<TEntityBase>());
            }
    
            /// <summary>
            /// 注册某个程序集中所有<typeparamref name="TEntityBase"/>的非抽象实体子类
            /// </summary>
            /// <typeparam name="TEntityBase">实体基类</typeparam>
            /// <param name="modelBuilder"></param>
            /// <param name="assembly">注册程序集</param>
            /// <param name="assembly">注册程序集</param>
            public static void RegisterEntitiesFromAssembly(this DbModelBuilder modelBuilder, Assembly assembly, Func<Type, bool> entityTypePredicate)
            {
                if (assembly == null)
                    throw new ArgumentNullException(nameof(assembly));
    
                //反射得到DbModelBuilder的Entity方法
                var entityMethod = modelBuilder.GetType().GetMethod("Entity");
    
                //反射得到ConfigurationRegistrar的Add<TEntityType>方法
                var addMethod = typeof(ConfigurationRegistrar)
                       .GetMethods()
                       .Single(m =>
                         m.Name == "Add"
                         && m.GetGenericArguments().Any(a => a.Name == "TEntityType"));
                //扫描所有fluent api配置类,要求父类型必须是EntityTypeConfiguration<TEntityType>
                var configTypes = assembly
                                   .GetTypesSafely()
                                   .Where(t =>
                                         !t.IsAbstract && t.BaseType != null && t.IsClass
                                         && t.BaseType.IsGenericType
                                         && t.BaseType.GetGenericTypeDefinition() == typeof(EntityTypeConfiguration<>)
                                         )
                                   .ToList();
    
                HashSet<Type> registedTypes = new HashSet<Type>();
    
                //存在fluent api配置的类,必须在Entity方法之前调用
                configTypes.ForEach(mappingType =>
                {
                    var entityType = mappingType.BaseType.GetGenericArguments().Single();
                    if (!entityTypePredicate(entityType))
                        return;
                    var map = Activator.CreateInstance(mappingType);
                    //反射调用ConfigurationRegistrar的Add方法注册fluent api配置,该方法会同时注册实体
                    addMethod.MakeGenericMethod(entityType)
                         .Invoke(modelBuilder.Configurations, new object[] { map });
    
                    registedTypes.Add(entityType);
                });
    
                //反射调用Entity方法 注册实体
                assembly
                    .GetTypesSafely()
                    .Where(entityTypePredicate)
                    .ForEach_(r =>
                    {
                        entityMethod.MakeGenericMethod(r).Invoke(modelBuilder, new object[0]);
                    });
            }
    View Code

    EFCore:

     1  /// <summary>
     2         /// 注册某个程序集中所有<typeparamref name="TEntityBase"/>的非抽象子类为实体
     3         /// </summary>
     4         /// <typeparam name="TEntityBase">实体基类</typeparam>
     5         /// <param name="modelBuilder"></param>
     6         /// <param name="assembly">注册程序集</param>
     7         public static void RegisterEntitiesFromAssembly<TEntityBase>(this ModelBuilder modelBuilder, Assembly assembly)
     8             where TEntityBase : class
     9         {
    10             modelBuilder.RegisterEntitiesFromAssembly(assembly, r => !r.IsAbstract && r.IsClass && r.IsChildTypeOf<TEntityBase>());
    11         }
    12 
    13         /// <summary>
    14         /// 注册某个程序集中所有<typeparamref name="TEntityBase"/>的非抽象子类为实体
    15         /// </summary>
    16         /// <typeparam name="TEntityBase">实体基类</typeparam>
    17         /// <param name="modelBuilder"></param>
    18         /// <param name="assembly">注册程序集</param>
    19         /// <param name="assembly">注册程序集</param>
    20         public static void RegisterEntitiesFromAssembly(this ModelBuilder modelBuilder, Assembly assembly, Func<Type, bool> entityTypePredicate)
    21         {
    22             if (assembly == null)
    23                 throw new ArgumentNullException(nameof(assembly));
    24 
    25             //反射得到ModelBuilder的ApplyConfiguration<TEntity>(...)方法
    26             var applyConfigurationMethod = modelBuilder.GetType().GetMethod("ApplyConfiguration");
    27 
    28             //所有fluent api配置类
    29             var configTypes = assembly
    30                                .GetTypesSafely()
    31                                .Where(t =>
    32                                  !t.IsAbstract && t.BaseType != null && t.IsClass
    33                                  && t.IsChildTypeOfGenericType(typeof(IEntityTypeConfiguration<>))).ToList();
    34 
    35             HashSet<Type> registedTypes = new HashSet<Type>();
    36             //存在fluent api配置的类,必须在Entity方法之前调用
    37             configTypes.ForEach(mappingType =>
    38             {
    39                 var entityType = mappingType.GetTypeInfo().ImplementedInterfaces.First().GetGenericArguments().Single();
    40 
    41                 //如果不满足条件的实体,不注册
    42                 if (!entityTypePredicate(entityType))
    43                     return;
    44 
    45                 var map = Activator.CreateInstance(mappingType);
    46                 applyConfigurationMethod.MakeGenericMethod(entityType)
    47                      .Invoke(modelBuilder, new object[] { map });
    48 
    49                 registedTypes.Add(entityType);
    50             });
    51 
    52             assembly
    53                 .GetTypesSafely()
    54                 .Where(r => !registedTypes.Contains(r))
    55                 .Where(entityTypePredicate)
    56                 .ForEach_(r =>
    57                 {
    58                     //直接调用Entity方法注册实体
    59                     modelBuilder.Entity(r);
    60                 });
    61         }
    View Code

    如何使用(EFCore,EF6类似)

            protected override void OnModelCreating(ModelBuilder modelBuilder)
            {
                modelBuilder.RegisterEntitiesFromAssembly<IEntity>(this.GetType().Assembly);
            }
    
    
    
                using (MyDbContext context = new MyDbContext())
                {
                    context.Set<Users>().FirstOrDefaultAsync(r => r.Name == "老王");
                }

    data nnotation和fluent api同时使用怎么用?,其中data nnotation与fluent api冲突时,以fluent api为准,如Users的表名称最终会映射为"Users___",见代码

     1     [Table("Users")]
     2     public class Users
     3     {
     4         [Key]
     5         public Guid Id { get; set; }
     6 
     7         [StringLength(10)]
     8         public string Name { get; set; }
     9     }
    10 
    11     public class UsersMapping : IEntityTypeConfiguration<Users>
    12     {
    13         public void Configure(EntityTypeBuilder<Users> builder)
    14         {
    15             builder.ToTable("Users___");            
    16         }
    17     }
    View Code

    不用你写 public DbSet<Users> Users{get;set;},也不用你写一大堆的,modelBuilder.ApplyConfiguration<Users>(new UserMpping());

    一句代码modelBuilder.RegisterEntitiesFromAssembly<IEntity>(this.GetType().Assembly);搞定所有的实体与实体配置

    代码:https://github.com/280780363/Lazy

  • 相关阅读:
    基于vue2.0 +vuex+ element-ui后台管理系统:包括本地开发调试详细步骤
    require.js实现js模块化编程(二):RequireJS Optimizer
    require.js实现js模块化编程(一)
    树型权限管理插件:jQuery Tree Multiselect详细使用指南
    表格组件神器:bootstrap table详细使用指南
    后台管理系统中的重点知识大全
    Ajax最详细的参数解析和场景应用
    npm常用命令小结
    详解javascript,ES5标准中新增的几种高效Object操作方法
    git入门学习(二):新建分支/上传代码/删除分支
  • 原文地址:https://www.cnblogs.com/gucaocao/p/8350120.html
Copyright © 2011-2022 走看看