• EF Core 实体映射表或视图


    ===============================================

     2020/8/12_第3次修改                       ccb_warlock

     

    更新说明:

    2020/8/12:

    1.增加了参考资料的内容

    2020/6/8:

    1.增加了在mysql上试验的结果说明;

    ===============================================

    最近忙于公司的业务系统,终于有时间对框架结构进行完善。在开发子系统时需要连接的是oracle中带用户名前缀的数据表(因为客户提供的是其他的用户),然而之前的框架实现中没有对这方面的内容做考虑(因为框架中EF Core实际只使用了MSSQL,而且业务只操作了当前库里的表(即dbo)),于是针对EF Core的实体映射还是单独写篇文章做个记录。

     

    2020/6/8,我在MySQL上也进行了试验,这种实体映射方式也是支持的。

     

    我在开发中采用的是Code First,所以这里不去深究记录的内容是否在DB First中可以应用。

     


    一、当前库/当前用户下,实体与表的映射

    在实现的过程中,有2种映射的处理(这里以用户实体举例):

    1)通过特性标记实体映射的表,再到DbContext中根据程序集的添加实体到模型中

    // 实体定义并定义表映射

    using System.ComponentModel.DataAnnotations;
    using System.ComponentModel.DataAnnotations.Schema;
    using Common.Entities;
    
    namespace Entity.Po
    {
        [Table("USER_T")]
        public class User : BaseEntity
        {
            [Column("NAME")]
            [DataType("varchar")]
            [MaxLength(30)]
            public string Name { get; set; }
            
            [Column("PASSWORD")]
            [DataType("varchar")]
            [MaxLength(50)]
            public string Password { get; set; }
        }
    }

    // 在模型中添加实体

    using Microsoft.EntityFrameworkCore;
    using System;
    using System.Collections.Generic;
    using System.Reflection;
    
    namespace Core.Dao
    {
        public class CommonDbContext : DbContext
        {
            private static Assembly _asmEntity;
    
            private static DbConfig _dbConfig;//这个是自定义的数据库配置,通过依赖注入获取
    
            private CommonDbContext(DbContextOptions options) : base(options)
            {
    
            }
    
            // todo:创建上下文等等
            
            protected override void OnModelCreating(ModelBuilder modelBuilder)
            {
                LoadModelBuilder(modelBuilder);
                base.OnModelCreating(modelBuilder);
            }
    
            private static void LoadModelBuilder(ModelBuilder modelBuilder)
            {
                if (null == _dbConfig) throw new Exception("DB Configuration Not Found.");
                
                _asmEntity = Assembly.Load("Entity");
                if (null == _asmEntity) throw new Exception("Entity Assembly Not Found.");
    
                var method = modelBuilder.GetType().GetMethod(
                    "Entity",
                    BindingFlags.Instance | BindingFlags.Public,
                    null,
                    new[] { typeof(Type) }, null
                );
    
                if (null == method) return;
    
                foreach (var type in _asmEntity.ExportedTypes)
                {
                    //设计在数据库配置信息中,增加了PO的基类标记,当该实体继承该基类,表示该实体是个PO
                    if (!type.IsSubclassOf(_dbConfig.BaseEntityClass)) continue;
    
                    modelBuilder.Entity(type);
                }
            }
        }
    }

    2)在DbContext中定义每个实体的DbSet,再在模型中添加实体并定义表映射

    // 实体定义

    using System.ComponentModel.DataAnnotations;
    using System.ComponentModel.DataAnnotations.Schema;
    using Common.Entities;
    
    namespace Entity.Po
    {
        public class User : BaseEntity
        {
            public string Name { get; set; }
            
            public string Password { get; set; }
        }
    }

    // 在模型中添加实体并定义表映射

    using Microsoft.EntityFrameworkCore;
    
    namespace Core.Dao
    {
        public class CommonDbContext : DbContext
        {
            public CommonDbContext(DbContextOptions<CommonDbContext> options) : base(options)
            {
            
            }
    
            // todo:创建上下文等等
            
            public DbSet<User> User { get; set; }
            
            protected override void OnModelCreating(ModelBuilder modelBuilder)
            {
                modelBuilder.Entity<User>(entity =>
                {
                    entity.ToTable("USER_T");
    
                    entity.Property(e => e.Id)
                        .HasColumnName("ID")
                        .HasColumnType("varchar")
                        .HasMaxLength(36);
                    
                    entity.Property(e => e.Dname)
                        .HasColumnName("NAME")
                        .HasColumnType("varchar")
                        .HasMaxLength(30);
                    
                    entity.Property(e => e.Password)
                        .HasColumnName("PASSWORD")
                        .HasColumnType("varchar")
                        .HasMaxLength(50);
                });
            }
        }
    }

    二、非当前库/非当前用户下,实体与表的映射(带前缀)

    在MSSQL中,当连接数据库ABC需要访问数据库DEF时,需要增加数据库前缀,如下:

    SELECT * FROM DEF.USER_T;

    在Oracle中,当用户A需要访问用户B的表时,需要增加用户前缀,如下:

    SELECT * FROM B.USER_T;

    直接在“一、当前库/当前用户下,实体与表的映射”的表名前增加前缀是无效的,运行后会提示表或视图不存在。

    查看官方文档(https://docs.microsoft.com/en-us/ef/core/modeling/entity-types?tabs=data-annotations)后,发现原来已经提供了一种统一的属性“表模式”来实现该前缀的标记。

    在实现的过程中,有2种映射的处理(这里以用户实体举例):

    1)通过特性标记实体映射的表,再到DbContext中根据程序集的添加实体到模型中

    // 实体定义并定义表映射(例如在MSSQL中,当连接数据库ABC需要访问数据库DEF时)

    using System.ComponentModel.DataAnnotations;
    using System.ComponentModel.DataAnnotations.Schema;
    using Common.Entities;
    
    namespace Entity.Po
    {
        [Table("USER_T", Schema = "DEF")]
        public class User : BaseEntity
        {
            [Column("NAME")]
            [DataType("varchar")]
            [MaxLength(30)]
            public string Name { get; set; }
            
            [Column("PASSWORD")]
            [DataType("varchar")]
            [MaxLength(50)]
            public string Password { get; set; }
        }
    }

    // 在模型中添加实体

    using Microsoft.EntityFrameworkCore;
    using System;
    using System.Collections.Generic;
    using System.Reflection;
    
    namespace Core.Dao
    {
        public class CommonDbContext : DbContext
        {
            private static Assembly _asmEntity;
    
            private static DbConfig _dbConfig;//这个是自定义的数据库配置,通过依赖注入获取
    
            private CommonDbContext(DbContextOptions options) : base(options)
            {
    
            }
    
            // todo:创建上下文等等
            
            protected override void OnModelCreating(ModelBuilder modelBuilder)
            {
                LoadModelBuilder(modelBuilder);
                base.OnModelCreating(modelBuilder);
            }
    
            private static void LoadModelBuilder(ModelBuilder modelBuilder)
            {
                if (null == _dbConfig) throw new Exception("DB Configuration Not Found.");
                
                _asmEntity = Assembly.Load("Entity");
                if (null == _asmEntity) throw new Exception("Entity Assembly Not Found.");
    
                var method = modelBuilder.GetType().GetMethod(
                    "Entity",
                    BindingFlags.Instance | BindingFlags.Public,
                    null,
                    new[] { typeof(Type) }, null
                );
    
                if (null == method) return;
    
                foreach (var type in _asmEntity.ExportedTypes)
                {
                    //设计在数据库配置信息中,增加了PO的基类标记,当该实体继承该基类,表示该实体是个PO
                    if (!type.IsSubclassOf(_dbConfig.BaseEntityClass)) continue;
    
                    modelBuilder.Entity(type);
                }
            }
        }
    }

    2)在DbContext中定义每个实体的DbSet,再在模型中添加实体并定义表映射

    // 实体定义

    using System.ComponentModel.DataAnnotations;
    using System.ComponentModel.DataAnnotations.Schema;
    using Common.Entities;
    
    namespace Entity.Po
    {
        public class User : BaseEntity
        {
            public string Name { get; set; }
            
            public string Password { get; set; }
        }
    }

    // 在模型中添加实体并定义表映射

    using Microsoft.EntityFrameworkCore;
    
    namespace Core.Dao
    {
        public class CommonDbContext : DbContext
        {
            public CommonDbContext(DbContextOptions<CommonDbContext> options) : base(options)
            {
            
            }
    
            // todo:创建上下文等等
            
            public DbSet<User> User { get; set; }
            
            protected override void OnModelCreating(ModelBuilder modelBuilder)
            {
                modelBuilder.HasDefaultSchema("DEF");
    
                modelBuilder.Entity<User>(entity =>
                {
                    entity.ToTable("USER_T");
    
                    entity.Property(e => e.Id)
                        .HasColumnName("ID")
                        .HasColumnType("varchar")
                        .HasMaxLength(36);
                    
                    entity.Property(e => e.Dname)
                        .HasColumnName("NAME")
                        .HasColumnType("varchar")
                        .HasMaxLength(30);
                    
                    entity.Property(e => e.Password)
                        .HasColumnName("PASSWORD")
                        .HasColumnType("varchar")
                        .HasMaxLength(50);
                });
            }
        }
    }

    using Microsoft.EntityFrameworkCore;
    
    namespace Core.Dao
    {
        public class CommonDbContext : DbContext
        {
            public CommonDbContext(DbContextOptions<CommonDbContext> options) : base(options)
            {
            
            }
    
            // todo:创建上下文等等
            
            public DbSet<User> User { get; set; }
            
            protected override void OnModelCreating(ModelBuilder modelBuilder)
            {
                modelBuilder.Entity<User>(entity =>
                {
                    entity.ToTable("USER_T", "DEF");
    
                    entity.Property(e => e.Id)
                        .HasColumnName("ID")
                        .HasColumnType("varchar")
                        .HasMaxLength(36);
                    
                    entity.Property(e => e.Dname)
                        .HasColumnName("NAME")
                        .HasColumnType("varchar")
                        .HasMaxLength(30);
                    
                    entity.Property(e => e.Password)
                        .HasColumnName("PASSWORD")
                        .HasColumnType("varchar")
                        .HasMaxLength(50);
                });
            }
        }
    }

    从框架的设计与代码的维护角度,我更推荐“使用特性标记实体映射的表”的方式。

    因为映射的特性将会在实体定义时一起维护,这样每次增删改实体时就不需要修改DbContext的源码,独立了该实体添加的功能。

     


    参考资料:

    1.https://docs.microsoft.com/en-us/ef/core/modeling/entity-types?tabs=data-annotations

     

     

  • 相关阅读:
    用webview打开网页时,里面有个div带滚动条的,但是在平板上滚动条失效
    PHP获取日期
    iScroll滚动区域中select、input、textarea元素无法点击的Bug修复
    用PHP获取系统时间时,时间比当前时间少8个小时
    kindeditor-4.1.7应用
    PHP连接SQLServer
    PHP常见方法
    APPLICATION ERROR #1502 .
    JSP 简介
    转发和重定向的区别与联系
  • 原文地址:https://www.cnblogs.com/straycats/p/12990558.html
Copyright © 2020-2023  润新知