You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

EF Core 6迁移中如何仅用特性消除影子属性(UserId1)

用特性解决EF Core 6中ApplicationUserRole生成UserId1/RoleId1影子属性的问题

问题现象

在EF Core 6迁移过程中,ApplicationUserRole实体自动生成了UserId1和RoleId1影子属性,错误提示如下:

The foreign key property 'ApplicationUserRole.RoleId1' was created in shadow state because a conflicting property with the simple name 'RoleId' exists in the entity type, but is either not mapped, is already used for another relationship, or is incompatible with the associated primary key type. See https://aka.ms/efcore-relationships for information on mapping relationships in EF Core.
The foreign key property 'ApplicationUserRole.UserId1' was created in shadow state because a conflicting property with the simple name 'UserId' exists in the entity type, but is either not mapped, is already used for another relationship, or is incompatible with the associated primary key type. See https://aka.ms/efcore-relationships for information on mapping relationships in EF Core.

已通过Fluent API实现解决,但需要改用**特性(Attributes)**完成配置。

原实体与上下文代码

ApplicationUser类

[Table("AspNetUsers")]
public class ApplicationUser : IdentityUser<int>
{
    [Key]
    [PersonalData]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public override int Id { get; set; }
    [NotMapped]
    public virtual ICollection<ApplicationUserClaim> Claims { get; set; }
    [NotMapped]
    public virtual ICollection<ApplicationUserLogin> Logins { get; set; }
    [NotMapped]
    public virtual ICollection<ApplicationUserToken> Tokens { get; set; }
    [NotMapped]
    [InverseProperty("User")]
    public virtual ICollection<ApplicationUserRole> UserRoles { get; set; }
}

ApplicationUserRole类

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.AspNetCore.Identity;

namespace OnlineStore.Entities;

[Table("AspNetUserRoles")]
public class ApplicationUserRole : IdentityUserRole<int>
{
    [Key]
    public override int UserId { get; set; }
    
    public virtual ApplicationUser User { get; set; } = null!;
    
    [ForeignKey(nameof(RoleId))]
    public virtual ApplicationRole Role { get; set; } = null!;
}

ApplicationContext类

using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using OnlineStore.Entities;

namespace OnlineStore.Contexts;

public class ApplicationContext
    : IdentityDbContext<ApplicationUser, ApplicationRole, int, ApplicationUserClaim, ApplicationUserRole, ApplicationUserLogin, ApplicationRoleClaim, ApplicationUserToken>
{
    public ApplicationContext(DbContextOptions<ApplicationContext> options) : base(options)
    {
    }

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

        var roles = new ApplicationRole[]
        {
            new ApplicationRole(ApplicationRole.User, 1),
            new ApplicationRole(ApplicationRole.Admin, 2),
        };

        builder.Entity<ApplicationRole>().HasData(roles);

        builder.Entity<ApplicationUserRole>()
            .HasOne(ur => ur.User)
            .WithMany(u => u.UserRoles)
            .HasForeignKey(ur => ur.UserId);
    }
}

特性实现方案

需要修改ApplicationUser和ApplicationUserRole类的特性配置,同时移除上下文里的Fluent API代码:

修改后的ApplicationUser类

[Table("AspNetUsers")]
public class ApplicationUser : IdentityUser<int>
{
    [Key]
    [PersonalData]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public override int Id { get; set; }
    [NotMapped]
    public virtual ICollection<ApplicationUserClaim> Claims { get; set; }
    [NotMapped]
    public virtual ICollection<ApplicationUserLogin> Logins { get; set; }
    [NotMapped]
    public virtual ICollection<ApplicationUserToken> Tokens { get; set; }
    // 移除[NotMapped],保留InverseProperty关联ApplicationUserRole的User导航属性
    [InverseProperty(nameof(ApplicationUserRole.User))]
    public virtual ICollection<ApplicationUserRole> UserRoles { get; set; }
}

修改后的ApplicationUserRole类

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.AspNetCore.Identity;

namespace OnlineStore.Entities;

[Table("AspNetUserRoles")]
public class ApplicationUserRole : IdentityUserRole<int>
{
    // 标记复合主键,指定顺序
    [Key, Column(Order = 0)]
    public override int UserId { get; set; }
    
    [Key, Column(Order = 1)]
    public override int RoleId { get; set; }

    // 用ForeignKey特性明确关联UserId
    [ForeignKey(nameof(UserId))]
    public virtual ApplicationUser User { get; set; } = null!;
    
    // 用ForeignKey特性明确关联RoleId
    [ForeignKey(nameof(RoleId))]
    public virtual ApplicationRole Role { get; set; } = null!;
}

修改后的ApplicationContext类

using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using OnlineStore.Entities;

namespace OnlineStore.Contexts;

public class ApplicationContext
    : IdentityDbContext<ApplicationUser, ApplicationRole, int, ApplicationUserClaim, ApplicationUserRole, ApplicationUserLogin, ApplicationRoleClaim, ApplicationUserToken>
{
    public ApplicationContext(DbContextOptions<ApplicationContext> options) : base(options)
    {
    }

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

        var roles = new ApplicationRole[]
        {
            new ApplicationRole(ApplicationRole.User, 1),
            new ApplicationRole(ApplicationRole.Admin, 2),
        };

        builder.Entity<ApplicationRole>().HasData(roles);

        // 移除原Fluent API配置,改用特性实现
    }
}

关键修改点说明

  1. ApplicationUser类:移除UserRoles属性的[NotMapped]特性,否则EF Core无法识别该导航属性,会自动生成影子属性。
  2. ApplicationUserRole类:
    • 为UserId和RoleId添加复合主键标记([Key, Column(Order = N)]),还原IdentityUserRole的复合主键结构,避免EF无法识别主键关联。
    • 为User和Role导航属性添加[ForeignKey]特性,明确指定对应的外键字段,消除EF的自动推断歧义。
  3. ApplicationContext类:移除原Fluent API的关系配置,确保特性配置生效。

内容的提问来源于stack exchange,提问作者Yaroslav Vorobyov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 03:41:22