.NET MVC Core 2.2 - 无法访问用户相关实体(外键)

RaV*_*RaV 1 c# asp.net-identity entity-framework-core .net-core asp.net-core

我正在写MVC Core 2中的第一个自己的应用程序,我无法访问具有用户外键的Estate Entity.我检查了我的数据库,遗产记录正确存储userId:

当我试图context.Estates.FirstOrDefault(m => m.Id == id);获得一个房地产实体时,但是User == null:

当我尝试通过以下方式访问它时:

var user = await _userManager.GetUserAsync(User);
var estate = user.Estates.FirstOrDefault(m => m.Id == id);
Run Code Online (Sandbox Code Playgroud)

我在Estates列表中得到null异常.同样试图以这种方式保存它给了我一个例外:

var user = await _userManager.GetUserAsync(User);
user.Estates.Add(estate);
Run Code Online (Sandbox Code Playgroud)

但是,当我这样输入时,它会在db中正确保存数据:

var user = await _userManager.GetUserAsync(User);
estate.User = user;
context.Add(estate);
Run Code Online (Sandbox Code Playgroud)

我不知道我在这里做错了什么.我在下面提供了我的代码,希望你能给我一些提示/建议.

这就是我如何基于IdentityDbContext构建上下文:

public class ReaContext : IdentityDbContext<User>
{
    public DbSet<Estate> Estates { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseNpgsql("Server=localhost;Port=5432;Database=rea-dev;User Id=postgres;Password=admin;");
    }

    public ReaContext(DbContextOptions<ReaContext> options)
        : base(options)
    { }

    public ReaContext()
        : base()
    { }
}
Run Code Online (Sandbox Code Playgroud)

我的用户型号:

public class User : IdentityUser
{
    public List<Estate> Estates { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

房地产模型:

public class Estate
{
    [Key]
    public int Id { get; set; }
    [MaxLength(100)]
    public string City { get; set; }

    public User User { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

这就是我如何添加服务:

services.AddDbContext<ReaContext>(options => options.UseNpgsql("Server=localhost;Port=5432;Database=rea-dev;User Id=postgres;Password=admin;"));

services.AddIdentity<User, IdentityRole>().AddEntityFrameworkStores<ReaContext>();
Run Code Online (Sandbox Code Playgroud)

我还提供Fluent Api迁移:

    migrationBuilder.CreateTable(
        name: "Estates",
        columns: table => new
        {
            Id = table.Column<int>(nullable: false)
                .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.SerialColumn),
            CreationDate = table.Column<DateTime>(nullable: false),
            UpdateDate = table.Column<DateTime>(nullable: false),
            ExpirationDate = table.Column<DateTime>(nullable: false),
            City = table.Column<string>(maxLength: 100, nullable: true),
            UserId = table.Column<string>(nullable: true)
        },
        constraints: table =>
        {
            table.PrimaryKey("PK_Estates", x => x.Id);
            table.ForeignKey(
                name: "FK_Estates_AspNetUsers_UserId",
                column: x => x.UserId,
                principalTable: "AspNetUsers",
                principalColumn: "Id",
                onDelete: ReferentialAction.Restrict);
        });

    migrationBuilder.CreateTable(
        name: "AspNetUsers",
        columns: table => new
        {
            Id = table.Column<string>(nullable: false),
            UserName = table.Column<string>(maxLength: 256, nullable: true),
            NormalizedUserName = table.Column<string>(maxLength: 256, nullable: true),
            Email = table.Column<string>(maxLength: 256, nullable: true),
            NormalizedEmail = table.Column<string>(maxLength: 256, nullable: true),
            EmailConfirmed = table.Column<bool>(nullable: false),
            PasswordHash = table.Column<string>(nullable: true),
            SecurityStamp = table.Column<string>(nullable: true),
            ConcurrencyStamp = table.Column<string>(nullable: true),
            PhoneNumber = table.Column<string>(nullable: true),
            PhoneNumberConfirmed = table.Column<bool>(nullable: false),
            TwoFactorEnabled = table.Column<bool>(nullable: false),
            LockoutEnd = table.Column<DateTimeOffset>(nullable: true),
            LockoutEnabled = table.Column<bool>(nullable: false),
            AccessFailedCount = table.Column<int>(nullable: false)
        },
        constraints: table =>
        {
            table.PrimaryKey("PK_AspNetUsers", x => x.Id);
        });
Run Code Online (Sandbox Code Playgroud)

Ham*_*eed 5

获取模型的相关数据有不同的方法.

  1. 预先加载:表示相关数据作为初始查询的一部分从数据库加载.
  2. 显式加载:表示以后从数据库中显式加载相关数据.
  3. 延迟加载:表示在访问导航属性时从数据库透明加载相关数据.

所以在您的情况下,您可以Eager loading通过执行以下操作来使用:

context.Estates.Include(e => e.User).FirstOrDefault(m => m.Id == id);
Run Code Online (Sandbox Code Playgroud)

有关更多信息,请阅读:加载相关数据.


编辑:实现的例子Eager loading patternIdentityUser:

您可以通过以下方式实现此目的

  1. 注射UserManager<User> _userManager.
  2. 创建自己ServiceService/Repository Design Pattern.

假设您选择了第一个选项.然后,您可以执行以下操作:

var user = await _userManager.Users
                 .Include(u => u.Estates)
                 .FirstOrDefaultAsync(YOUR_CONDITION);
Run Code Online (Sandbox Code Playgroud)