C# .NET MVC Core 2.2-Can';t访问用户相关实体(外键)

C# .NET MVC Core 2.2-Can';t访问用户相关实体(外键),c#,asp.net-core,.net-core,asp.net-identity,entity-framework-core,C#,Asp.net Core,.net Core,Asp.net Identity,Entity Framework Core,我正在MVC Core 2中编写我自己的第一个应用程序,我在访问具有用户外键的地产实体时遇到问题。我已检查我的数据库,房地产记录正确存储用户ID: 当我尝试获取context.Estates.FirstOrDefault(m=>m.Id==Id)时我得到一个地产实体,但带有User==null: 当我尝试通过以下方式访问它时: var user = await _userManager.GetUserAsync(User); var estate = user.Estates.FirstOr

我正在MVC Core 2中编写我自己的第一个应用程序,我在访问具有用户外键的地产实体时遇到问题。我已检查我的数据库,房地产记录正确存储用户ID:

当我尝试获取
context.Estates.FirstOrDefault(m=>m.Id==Id)时我得到一个地产实体,但带有
User==null

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

var user = await _userManager.GetUserAsync(User);
var estate = user.Estates.FirstOrDefault(m => m.Id == id);
我在不动产清单上得到空的例外。同样尝试以这种方式保存它也会给我一个例外:

var user = await _userManager.GetUserAsync(User);
user.Estates.Add(estate);
但是,当我这样键入时,它会将数据正确地保存在db中:

var user = await _userManager.GetUserAsync(User);
estate.User = user;
context.Add(estate);
我不知道我在这里做错了什么。我在下面提供我的代码,希望你能给我一些提示/建议

这就是我如何基于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()
    { }
}
这就是我添加服务的方式:

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

services.AddIdentity<User, IdentityRole>().AddEntityFrameworkStores<ReaContext>();
services.AddDbContext(options=>options.UseNpgsql(“服务器=localhost;端口=5432;数据库=rea-dev;用户Id=postgres;密码=admin;”);
services.AddIdentity().AddEntityFrameworkStores();
我还提供流畅的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);
        });
migrationBuilder.CreateTable(
名称:“不动产”,
列:表=>new
{
Id=table.Column(可空:false)
.Annotation(“Npgsql:ValueGenerationStrategy”,NpgsqlValueGenerationStrategy.SerialColumn),
CreationDate=表.列(可空:false),
UpdateDate=table.Column(可空:false),
ExpirationDate=table.Column(可空:false),
City=table.Column(最大长度:100,可为空:true),
UserId=table.Column(可空:true)
},
约束:表=>
{
表.PrimaryKey(“PK_地产”,x=>x.Id);
表1.外键(
名称:“FK_Estates_AspNetUsers_UserId”,
列:x=>x.UserId,
原则性:“AspNetUsers”,
主栏:“Id”,
onDelete:referentialiction.Restrict);
});
migrationBuilder.CreateTable(
名称:“AspNetUsers”,
列:表=>new
{
Id=table.Column(可空:false),
UserName=table.Column(最大长度:256,可为空:true),
NormalizedUserName=table.Column(maxLength:256,null:true),
Email=table.Column(最大长度:256,可为空:true),
NormalizedEmail=table.Column(maxLength:256,nullable:true),
emailconfirm=table.Column(可空:false),
PasswordHash=table.Column(可空:true),
SecurityStamp=table.Column(可空:true),
ConcurrencyStamp=table.Column(可空:true),
PhoneNumber=table.Column(可空:true),
PhoneNumberConfiged=table.Column(可空:false),
TwoFactorEnabled=table.Column(可空:false),
LockoutEnd=table.Column(可空:true),
LockoutEnabled=table.Column(可空:false),
AccessFailedCount=table.Column(可空:false)
},
约束:表=>
{
表.PrimaryKey(“PK_AspNetUsers”,x=>x.Id);
});

获取模型相关数据的方法多种多样

  • 即时加载:表示从数据库加载相关数据作为初始查询的一部分
  • 显式加载:表示以后从数据库显式加载相关数据
  • 延迟加载:表示在访问导航属性时,相关数据从数据库透明加载
  • 因此,在您的情况下,您可以通过执行以下操作来使用
    快速加载

    context.Estates.Include(e => e.User).FirstOrDefault(m => m.Id == id);
    
    var user = await _userManager.Users
                     .Include(u => u.Estates)
                     .FirstOrDefaultAsync(YOUR_CONDITION);
    

    有关更多信息,请阅读以下内容:


    编辑:在
    IdentityUser
    上实现
    快速加载模式的示例:

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

  • 注入
    UserManager\u UserManager
  • 服务/存储库设计模式中创建自己的
    服务
  • 假设你选择了第一个选项。然后您可以执行以下操作:

    context.Estates.Include(e => e.User).FirstOrDefault(m => m.Id == id);
    
    var user = await _userManager.Users
                     .Include(u => u.Estates)
                     .FirstOrDefaultAsync(YOUR_CONDITION);
    

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

  • 即时加载:表示从数据库加载相关数据作为初始查询的一部分
  • 显式加载:表示以后从数据库显式加载相关数据
  • 延迟加载:表示在访问导航属性时,相关数据从数据库透明加载
  • 因此,在您的情况下,您可以通过执行以下操作来使用
    快速加载

    context.Estates.Include(e => e.User).FirstOrDefault(m => m.Id == id);
    
    var user = await _userManager.Users
                     .Include(u => u.Estates)
                     .FirstOrDefaultAsync(YOUR_CONDITION);
    

    有关更多信息,请阅读以下内容:


    编辑:在
    IdentityUser
    上实现
    快速加载模式的示例:

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

  • 注入
    UserManager\u UserManager
  • 服务/存储库设计模式中创建自己的
    服务
  • 假设你选择了第一个选项。然后您可以执行以下操作:

    context.Estates.Include(e => e.User).FirstOrDefault(m => m.Id == id);
    
    var user = await _userManager.Users
                     .Include(u => u.Estates)
                     .FirstOrDefaultAsync(YOUR_CONDITION);
    

    谢谢,我找到了一个用于延迟加载的应用程序,我添加了
    Microsoft.EntityFrameworkCore.Proxies
    包,并如文档所述将我的关系更改为虚拟。现在它工作得很好。非常感谢,因为我不知道加载类型,所以我被困在这几个小时里。出于好奇,有没有办法通过快速加载访问
    user.estate
    ?我找到了一些示例,但都是在context对象上,用户没有
    include
    方法。它适用于延迟加载。我认为是的,你可以。通过注入
    UserManager\u UserManager
    ,您可以以答案中所示的类似方式使用它。我将用一个例子更新答案。我的意思是针对单用户对象,比如在
    var user=await\u userManager.GetUserAsync(user);user.Estates.DoStuff(),但如果没有