.NET MVC Core 2.2 - 无法访问用户相关实体(外键)
.NET MVC Core 2.2 - Can't access user related entity (foreign key)
我正在 MVC Core 2 中编写自己的第一个应用程序,但在访问具有用户外键的 Estate 实体时遇到问题。我检查了我的数据库,Estate 记录正确存储了 userId:
当我尝试获取 context.Estates.FirstOrDefault(m => m.Id == id);
时,我得到了一个 Estate 实体,但是 User == null
:
当我尝试通过 :
访问它时
var user = await _userManager.GetUserAsync(User);
var estate = user.Estates.FirstOrDefault(m => m.Id == id);
我在 Estates 列表中得到空异常。也试图以这种方式保存它给了我一个例外:
var user = await _userManager.GetUserAsync(User);
user.Estates.Add(estate);
然而,当我这样输入时,它会在 db:
中正确保存数据
var user = await _userManager.GetUserAsync(User);
estate.User = user;
context.Add(estate);
我不知道我在这里做错了什么。我在下面提供我的代码,希望你能给我一些tips/advices。
这就是我基于 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()
{ }
}
我的用户模型:
public class User : IdentityUser
{
public List<Estate> Estates { get; set; }
}
地产模型:
public class Estate
{
[Key]
public int Id { get; set; }
[MaxLength(100)]
public string City { get; set; }
public User User { get; set; }
}
这就是我添加服务的方式:
services.AddDbContext<ReaContext>(options => options.UseNpgsql("Server=localhost;Port=5432;Database=rea-dev;User Id=postgres;Password=admin;"));
services.AddIdentity<User, IdentityRole>().AddEntityFrameworkStores<ReaContext>();
我还提供 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);
});
有多种方法可以获取模型的相关数据。
- Eager loading: 表示相关数据作为初始查询的一部分从数据库中加载。
- 显式加载: 表示相关数据是稍后从数据库中显式加载的。
- 延迟加载:表示访问导航属性时从数据库透明加载相关数据
因此,在您的情况下,您可以通过执行以下操作来使用 Eager loading
:
context.Estates.Include(e => e.User).FirstOrDefault(m => m.Id == id);
有关更多信息,请阅读:Loading Related Data。
编辑:在 IdentityUser
上实现 Eager loading pattern
的示例:
您可以通过以下任一方式实现:
- 注入
UserManager<User> _userManager
.
- 创建您自己的
Service
,如 Service/Repository Design Pattern
。
假设您选择了第一个选项。然后您可以执行以下操作:
var user = await _userManager.Users
.Include(u => u.Estates)
.FirstOrDefaultAsync(YOUR_CONDITION);
我正在 MVC Core 2 中编写自己的第一个应用程序,但在访问具有用户外键的 Estate 实体时遇到问题。我检查了我的数据库,Estate 记录正确存储了 userId:
当我尝试获取 context.Estates.FirstOrDefault(m => m.Id == id);
时,我得到了一个 Estate 实体,但是 User == null
:
当我尝试通过 :
访问它时var user = await _userManager.GetUserAsync(User);
var estate = user.Estates.FirstOrDefault(m => m.Id == id);
我在 Estates 列表中得到空异常。也试图以这种方式保存它给了我一个例外:
var user = await _userManager.GetUserAsync(User);
user.Estates.Add(estate);
然而,当我这样输入时,它会在 db:
中正确保存数据var user = await _userManager.GetUserAsync(User);
estate.User = user;
context.Add(estate);
我不知道我在这里做错了什么。我在下面提供我的代码,希望你能给我一些tips/advices。
这就是我基于 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()
{ }
}
我的用户模型:
public class User : IdentityUser
{
public List<Estate> Estates { get; set; }
}
地产模型:
public class Estate
{
[Key]
public int Id { get; set; }
[MaxLength(100)]
public string City { get; set; }
public User User { get; set; }
}
这就是我添加服务的方式:
services.AddDbContext<ReaContext>(options => options.UseNpgsql("Server=localhost;Port=5432;Database=rea-dev;User Id=postgres;Password=admin;"));
services.AddIdentity<User, IdentityRole>().AddEntityFrameworkStores<ReaContext>();
我还提供 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);
});
有多种方法可以获取模型的相关数据。
- Eager loading: 表示相关数据作为初始查询的一部分从数据库中加载。
- 显式加载: 表示相关数据是稍后从数据库中显式加载的。
- 延迟加载:表示访问导航属性时从数据库透明加载相关数据
因此,在您的情况下,您可以通过执行以下操作来使用 Eager loading
:
context.Estates.Include(e => e.User).FirstOrDefault(m => m.Id == id);
有关更多信息,请阅读:Loading Related Data。
编辑:在 IdentityUser
上实现 Eager loading pattern
的示例:
您可以通过以下任一方式实现:
- 注入
UserManager<User> _userManager
. - 创建您自己的
Service
,如Service/Repository Design Pattern
。
假设您选择了第一个选项。然后您可以执行以下操作:
var user = await _userManager.Users
.Include(u => u.Estates)
.FirstOrDefaultAsync(YOUR_CONDITION);