EF Core Fluent API 使用映射表[子表]进行一对多映射

问题描述 投票:0回答:1

我正在尝试使用 EF Core Fluent API 创建一对多映射。

我有这3张桌子:

  • User
  • Role
  • 用户角色映射表

Table Mapping

这些 C# 类代表这些表:

public class User
{
    public string Id { get; set; }
    public string Email { get; set; }
}

public class Role
{
    public string Id { get; set; }
    public string RoleName { get; set; }
}

public class UserRoleMapping
{
    public string Id { get; set; }
    public string UserId { get; set; }
    public string RoleId { get; set; }
}

使用

IEntityTypeConfiguration<TEntity> where TEntity : class
Fluent api 配置已为
User
Role
表完成,但我无法为
UserRoleMapping
表进行 Fluent API 配置。

当我尝试跑步时:

var role = await uow.RoleRepository
                    .GetAsync(_ => _.Active,
                              _ => _.OrderByDescending(s => s.CreatedDate), 
                              s => s.UserRole.User);

我的期望是我应该能够使用该查询,当获取角色时还需要获取关联的用户信息,这是我无法执行的。
下面是配置

internal class UserConfig : BaseEntityConfig<UserEntity>
    {
        private readonly string TableName = DatabaseTableName.User;

        public override void Configure(EntityTypeBuilder<UserEntity> builder)
        {
            builder
                .ToTable(TableName);
            builder.HasKey(_ => _.Id);
     
            builder.Property(_ => _.Email).HasColumnName("email_address");

            builder
                .HasOne(_ => _.UserRole)
                .WithOne(_=>_.User)
                .HasForeignKey<UserRoleEntity>(_ => _.UserId);

            //builder.HasOne(_ => _.UserRole)
            //    .WithOne(_ => _.User)
            //    .HasForeignKey<UserRoleEntity>(_ => _.RoleId);

            //builder.Property(_ => _.UserRole).HasColumnName("UserRole");



            base.Configure(builder);
        }
    }

角色配置

internal class RoleConfig : BaseEntityConfig<RoleEntity>
    {
        private readonly string TableName = DatabaseTableName.Role;

        public override void Configure(EntityTypeBuilder<RoleEntity> builder)
        {
            builder
                .ToTable(TableName);
            builder.HasKey(_ => _.Id);
            builder.Property(_ => _.RoleName).HasColumnName("name");
            builder.HasOne(_ => _.UserRole)
                .WithOne(_ => _.Role)
                .HasForeignKey<UserRoleEntity>(_ => _.RoleId);
           base.Configure(builder);
        }
    }
entity-framework-core entity-relationship ef-fluent-api
1个回答
0
投票

这是多对多关系,而不是一对多。通常,您会取消 UserRole 表上的“Id”,并使用基于 UserId + RoleId 的复合 PK。您的配置试图建立一对一的关系。 (

HasOne().WithOne()
) 一对多会看到一个 User 有一个 RoleId,其中一个“角色”与多个“用户”相关联。这不太可能是您正在寻找的关系与多对多的关系。这些用户属于这些角色。所以一个用户可以有多个角色,一个角色可以有多个用户。

public class User
{
    public string Id { get; set; }
    public string Email { get; set; }
    public virtual ICollection<Role> Roles { get; } = [];
}

public class Role
{
    public string Id { get; set; }
    public string RoleName { get; set; }
    public virtual ICollection<User> Users { get; } = [];
}

然后配置时:

// 用户EntityTypeConfig

builder
     .HasMany(_ => _.Roles)
     .WithMany(_=>_.Users)
     .UsingEntity("UserRole",
          l => l.HasOne(typeof(Role))
               .WithMany()
               .HasForeignKey("RoleId")
               .HasPrincipalKey(nameof(Role.Id)),
          r => r.HasOne(typeof(User))
               .WithMany()
               .HasForeignKey("UserId")
               .HasPrincipalKey(nameof(User.Id)),
        j => j.HasKey("UserId", "RoleId"));

这会在没有 UserRole 实体的情况下配置它,但也可以使用定义的实体类或通过

Dictionary
进行设置。文档中概述了一些选项。 (https://learn.microsoft.com/en-us/ef/core/modeling/relationships/many-to-many

如果您确实希望通过 UserRole 建立关系,例如,如果您希望为用户和角色之间关系的每个实例添加一些属性到 UserRole,那么可以在关系中显式设置它,但更多的是作为多个-一对多来模仿多对多:

 public class User
{
    public string Id { get; set; }
    public string Email { get; set; }
    public virtual ICollection<UserRole> UserRoles { get; } = [];
}

public class Role
{
    public string Id { get; set; }
    public string RoleName { get; set; }
    public virtual ICollection<UserRole> UserRoles { get; } = [];
}

// User EntityTypeConfig

builder
     .HasMany(_ => _.UserRoles)
     .WithOne(_=> _.User)
     .HasForeignKey(_ => _.UserId);

// Role EntityTypeConfig

builder
     .HasMany(_ => _.UserRoles)
     .WithOne(_=> _.Role)
     .HasForeignKey(_ => _.RoleId);

// UserRole EntityTypeConfig

builder.HasKey(_ => new { _.UserId, _.RoleId } ); // or _.Id if you want a  dedicated Id column.

使用显式实体的缺点是从角色到用户或从用户到角色不太方便。您需要通过 UserRoles。即

role.UserRoles.Select(_ => _.User);

而不是:

role.Users;

通常仅当您需要额外的属性时才需要映射关联实体,例如,如果您想记录用户与角色关联的日期时间。 UserRole 将具有 CreatedDateTime,因此我们需要映射 UserRole 才能访问此属性。 (与创建用户时用户的 CreatedDateTime 或创建角色时角色的 CreatedDateTime 相比。)

© www.soinside.com 2019 - 2024. All rights reserved.