• EF Core中通过Fluent API配置多对多关系


    EF Core与EF不是完全一样的,官方文档列出了详细的差异比较,可以查阅:https://docs.microsoft.com/zh-cn/ef/efcore-and-ef6/。

    EF Core支持Code First模式生成数据库。这里以权限管理中的用户-角色-菜单的关系为例,演示一下EF Core中如何通过手动编写Fluent API来配置多对多的关系。

    测试环境:VS2022 / .NET 6.0 / EF Core 6.0

    假设我们已经设计好了数据库,并建立了主外键关联。如下图所示,一个用户可以对应多个角色,一个角色可以对应多个菜单。

    我们首先要准备好上面的表对应的类:

    用户类:

    查看代码
    
    /// <summary>
        /// 用户
        /// </summary>
        public class User
        {
            /// <summary>
            /// GUID
            /// </summary>
            [Key]
            public string? No { get; set; }
    
            /// <summary>
            /// 用户Id
            /// </summary>
            public string? Id { get; set; }
    
            /// <summary>
            /// 用户名
            /// </summary>
            public string? UserName { get; set; }
    
            /// <summary>
            /// 密码
            /// </summary>
            public string? PassWord { get; set; }
    
            /// <summary>
            /// 姓名
            /// </summary>
            public string? Name { get; set; }
    
            /// <summary>
            /// 性别
            /// </summary>
            public string? Sex { get; set; }
    
            /// <summary>
            /// 部门
            /// </summary>
            public string? DeptId { get; set; }
    
            /// <summary>
            /// 工号
            /// </summary>
            public string? JobNumber { get; set; }
    
            /// <summary>
            /// 职位
            /// </summary>
            public string? Position { get; set; }
    
            /// <summary>
            /// 标识
            /// </summary>
            public int Flag { get; set; }
    
            /// <summary>
            /// 最后登录时间
            /// </summary>
            public DateTime LastLoginTime { get; set; }
    
            /// <summary>
            /// 备注
            /// </summary>
            public string? Remark { get; set; }
    
            /// <summary>
            /// 一个用户可以对应多个角色
            /// </summary>
            public virtual ICollection<Role> Role { get; set; }
        }

    角色类:

    查看代码
    
    /// <summary>
        /// 角色
        /// </summary>
        public class Role
        {
            /// <summary>
            /// GUID
            /// </summary>
            [Key]
            public string? No { get; set; }
    
            /// <summary>
            /// 角色Id
            /// </summary>
            public string? Id { get; set; }
    
            /// <summary>
            /// 角色名
            /// </summary>
            public string? Name { get; set; }
    
            /// <summary>
            /// 状态标识
            /// </summary>
            public int Flag { get; set; }
    
            /// <summary>
            /// 角色备注
            /// </summary>
            public string? Remark { get; set; }
    
            /// <summary>
            /// 一个角色对应多个菜单
            /// </summary>
            public virtual ICollection<Function>? Function { get; set; }
    
            /// <summary>
            /// 一个角色对应多个用户
            /// </summary>
            public virtual ICollection<User>? User { get; set; }
        }

    菜单类:

    查看代码
    
    /// <summary>
        /// 功能菜单
        /// </summary>
        public class Function
        {
            /// <summary>
            /// 功能编号
            /// </summary>
            public string? Id { get; set; }
    
            /// <summary>
            /// 功能名称
            /// </summary>
            public string? Name { get; set; }
    
            /// <summary>
            /// 父级编号
            /// </summary>
            public string? ParentId { get; set; }
    
            /// <summary>
            /// 链接地址
            /// </summary>
            public string? Url { get; set; }
    
            /// <summary>
            /// 链接顺序
            /// </summary>
            public int Order { get; set; }
    
            /// <summary>
            /// 菜单级别
            /// </summary>
            public int Type { get; set; }
    
            /// <summary>
            /// 菜单标志
            /// </summary>
            public int Flag { get; set; }
    
            /// <summary>
            /// 菜单说明
            /// </summary>
            public string? Remark { get; set; }
    
            /// <summary>
            /// 一个菜单可以被多个角色引用
            /// </summary>
            public virtual ICollection<Role>? Role { get; set; }
        }

    然后需要创建一个EF上下文来操作数据库:

    public class MyDbContext : DbContext
    {
        public MyDbContext()
        {
    
        }
    
        public MyDbContext(DbContextOptions<MyDbContext> options)
            : base(options)
        {
        }
    
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
    
            //modelBuilder.Entity<User>()
            //    .HasMany(o => o.Role)
            //    .WithMany(o => o.User)
            //    .UsingEntity<UserRole>(
            //        o => o.HasOne(o => o.Role).WithMany().HasForeignKey(o => o.Role_No),
            //        o => o.HasOne(o => o.User).WithMany().HasForeignKey(o => o.User_No),
            //        o => o.HasKey(t => new { t.User_No, t.Role_No })
            //    );
    
            modelBuilder.Entity<User>()
             .HasMany(o => o.Role)
             .WithMany(o => o.User)
             .UsingEntity<Dictionary<string, object>>("UserRole",
                 o => o.HasOne<Role>().WithMany().HasForeignKey("Role_No"),
                 o => o.HasOne<User>().WithMany().HasForeignKey("User_No"),
                 o => o.ToTable("UserRole"));
    
            modelBuilder.Entity<Role>()
                .HasMany(o => o.Function)
                .WithMany(o => o.Role)
                .UsingEntity<Dictionary<string, object>>("RoleFunction",
                    o => o.HasOne<Function>().WithMany().HasForeignKey("Function_Id"),
                    o => o.HasOne<Role>().WithMany().HasForeignKey("Role_No"),
                    o => o.ToTable("RoleFunction"));
        }
    
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            base.OnConfiguring(optionsBuilder);
            optionsBuilder.UseSqlServer("server=xxx.xxx.xxx.xxx;database=数据库名称;uid=数据库账号;pwd=数据库密码;");
        }
    
        public DbSet<User> User { get; set; }
    
        public DbSet<Role> Role { get; set; }
    
        public DbSet<Function> Function { get; set; }
    
    }

    上述代码中的注释部分需要创建一个UserRole中间表对应的类:

    [Table("UserRole")]
    public class UserRole
    {
        public string User_No { get; set; }
    
        public string Role_No { get; set; }
    
        [NotMapped]
        public User User { get; set; }
    
        [NotMapped]
        public Role Role { get; set; }
    }

    而下面的Dictionary的方式则不需要创建这个类。

    Fluent API方式手动配置好关系之后,就可以使用了:

    using (var db = new MyDbContext())
    {
        //当前用户对应多个角色
        List<Role> roles = db.User
            .Include(o => o.Role)
            .ThenInclude(o => o.Function)
            .FirstOrDefault(t => t.UserName.Equals("admin"))
            .Role
            .ToList();
    }

    通过Include来预先加载关联的Role,再通过ThenInclude实现预先加载多级关联。查询角色对应的菜单也是类似的方式。

  • 相关阅读:
    mysql5.6 TIME,DATETIME,TIMESTAMP
    CMake 简单介绍 图
    mysql 源码编绎修改 FLAGS,调试MYSQL
    CHAR 详解
    关于MySQL的各种总结
    Shell编程速查手册
    cmake 手册系列
    编译安装GCC 5.2.0
    宽字符相关的输入输出
    Makefile
  • 原文地址:https://www.cnblogs.com/guwei4037/p/16105445.html
Copyright © 2020-2023  润新知