我正在尝试将应用程序用户与UserTask应用程序表相关联。但是我得到了下面的错误
InvalidOperationException:无法确定由"UserTask"类型的导航属性"ApplicationUser.UserTask"表示的关系。手动配置关系,或使用"[NotMapped]"特性或使用"OnModelCreating"中的"EntityTypeBuilder.ignore"忽略此属性
我使用NetCore 2.0.3
public class UserTask
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int UserTaskID { get; set; }
public string Description { get; set; }
[ForeignKey("OwnerUserID")]
public string TaskOwnerId { get; set; }
[ForeignKey("ExecutorUserID")]
public string TaskExecutorId { get; set; }
public virtual ApplicationUser OwnerUserID { get; set; }
public virtual ApplicationUser ExecutorUserID { get; set; }
}
public class ApplicationUser : IdentityUser
{
[ForeignKey("UserTaskID")]
public int UserTaskID { get; set; }
public UserTask UserTask { get; set; }
}
控制器
public IActionResult Create()
{
ViewData["TaskOwnerId"] = new SelectList(_userManager.Users.ToList(), "Id", "Name");
ViewData["TaskExecutorId"] = new SelectList(_userManager.Users.ToList(), "Id", "Name");
return View();
}
// POST: UserTasks/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("UserTaskID,Description,TaskOwnerId,TaskExecutorId")] UserTask userTask)
{
if (ModelState.IsValid)
{
_context.Add(userTask);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
ViewData["TaskOwnerId"] = new SelectList(_userManager.Users.ToList(), "Id", "Name", userTask.TaskOwnerId);
ViewData["TaskExecutorId"] = new SelectList(_userManager.Users.ToList(), "Id", "Name", userTask.TaskExecutorId);
return View(userTask);
}
和视图
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Description" class="control-label"></label>
<input asp-for="Description" class="form-control" />
<span asp-validation-for="Description" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="TaskOwnerId" class="control-label"></label>
<select asp-for="TaskOwnerId" class="form-control" asp-items="ViewBag.TaskOwnerId"></select>
</div>
<div class="form-group">
<label asp-for="TaskExecutorId" class="control-label"></label>
<select asp-for="TaskExecutorId" class="form-control" asp-items="ViewBag.TaskExecutorId"></select>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</form>
</div>
</div>
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Description" class="control-label"></label>
<input asp-for="Description" class="form-control" />
<span asp-validation-for="Description" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="TaskOwnerId" class="control-label"></label>
<select asp-for="TaskOwnerId" class="form-control" asp-items="ViewBag.TaskOwnerId"></select>
</div>
<div class="form-group">
<label asp-for="TaskExecutorId" class="control-label"></label>
<select asp-for="TaskExecutorId" class="form-control" asp-items="ViewBag.TaskExecutorId"></select>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</form>
</div>
</div>
你能帮我吗?
像一样尝试
public class UserTask
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int UserTaskID { get; set; }
public string Description { get; set; }
public ApplicationUser ApplicationUser {get; set; }
}
public class ApplicationUser : IdentityUser
{
public ICollection<UserTask> UserTask { get; set; }
}
在ApplicationDbContext类中
protected override void OnModelCreating(ModelBuilder modelBuilder){
modelBuilder.Entity<ApplicationUser>()
.HasMany(a => a.UserTask)
.WithOne(b => b.ApplicationUser);}
您的问题有两个方面:
-
ApplicationUser
上的UserTask
只有一个导航属性。UserTask
上的ApplicationUser
有两个不同的导航属性,EF不能将两个关系都映射到另一侧的一个外键,所以如果一侧有两个导航属性,那么另一侧也需要两个。例如:public UserTask OwnedUserTask { get; set; } public UserTask ExecutedUserTask { get; set; }
-
假设同一实体有两个关系,EF不知道
UserTask
上的哪个关系映射到ApplicationUser
上的哪个,所以您必须配置以下内容:protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<ApplicationUser>() .HasOne(x => x.OwnedUserTask) .WithOne(x => x.OwnerUser); modelBuilder.Entity<ApplicationUser>() .HasOne(x => x.ExecutedUserTask) .WithOne(x => x.ExecutorUser); }
也就是说,这是一对一的关系实际上没有意义。任务通常是你有多个任务的(如果我只有一个任务要执行就好了!)。因此,这可能是一对多,这将需要您将ApplicationUser
更改为类似的内容
public class ApplicationUser : IdentityUser
{
public ICollection<UserTask> OwnedUserTasks { get; set; }
public ICollection<UserTask> ExecutedUserTasks { get; set; }
}
即使进行了更改,仍然存在与以前相同的问题:您有两个到同一实体的关系,所以您必须添加配置来告诉EF如何处理这一问题。只是,现在,您将使用HasMany
而不是HasOne
:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<ApplicationUser>()
.HasMany(x => x.OwnedUserTasks)
.WithOne(x => x.OwnerUser);
modelBuilder.Entity<ApplicationUser>()
.HasMany(x => x.ExecutedUserTasks)
.WithOne(x => x.ExecutorUser);
}
最后,值得一提的是,您可以在关系的任何一方配置它。换句话说,你可以先做Entity<UserTask>
,然后再做HasOne(x => x.OwnerUser).WithMany(x => x.OwnedUserTasks)
。走哪条路完全取决于你。