【发布时间】:2021-11-24 22:03:09
【问题描述】:
我正在开发一个 .NET Core 3.1 Razor 页面应用程序。我正在使用 Entity Framework Core 和具有通用存储库的工作单元模式。我还使用 AddScoped 来注册我的所有服务,例如UnitOfWork 和 Repositories 等,即每个 HttpRequest 在存储库之间共享一个 DbContext。
services.AddDbContextPool<MyContext>(opt => opt.UseSqlServer(Configuration.GetConnectionString("MyConnection"))
.EnableSensitiveDataLogging());
services.AddScoped<IUnitOfWork, UnitOfWork>();
services.AddScoped<IGenericRepository<Domain.List>, ListRepository>();
services.AddScoped<IGenericRepository<Domain.ListItem>, ListItemRepository>();
//etc...
我为用户编写了一些代码来更新他们的姓名和电子邮件。一旦用户输入数据,我调用一个函数 UserAlreadyExists 来验证电子邮件地址是否已经存在于数据库中。此验证码用于在应用程序上注册的新用户,也用于已经注册并正在更新其详细信息的用户。当现有用户尝试更新其详细信息时,将使用以下代码。
public IUnitOfWork UoW { get; set; }
[BindProperty]
public Domain.User UserObj { get; set; }
public IActionResult OnPost()
{
if(ModelState.IsValid)
{
if(UserObj.Id > 0)
{
//Update user
//Validation to ensure if email updated, it's not already in use
if(UserAlreadyExists(UserObj))
{
TempData["Message"] = "Email address already exists within database.";
return Page();
}
UoW.UserRepository.Update(UserObj);
UoW.SaveChanges();
TempData["Message"] = "User updated.";
}
else
{
//Add user code here
}
return RedirectToPage("List");
}
return Page();
}
这是检查用户是否存在的代码
private bool UserAlreadyExists(Domain.User user)
{
bool alreadyExists = true;
var existingUser = UoW.UserRepository
.Find(u => u.Email.Trim().ToUpper() == user.Email.Trim().ToUpper())
.FirstOrDefault();
// Existing user
if (existingUser == null)
{
alreadyExists = false;
}
else if (user.Email == existingUser.Email)
{
if (user.Id == existingUser.Id)
{
//User updating their details, but not their email
alreadyExists = false;
}
}
return alreadyExists;
}
当现有用户尝试更新其姓名时,我收到此错误:
无法跟踪实体类型“用户”的实例,因为已在跟踪另一个具有键值“{Id: 1}”的实例。附加现有实体时,请确保仅附加一个具有给定键值的实体实例
我了解错误,它发生在 UserAlreadyExists 函数内部。当现有用户尝试更新其姓名时,User 实体将传递到函数中,并且该实体包含主键。然后我在名为existingUser 的验证函数中创建另一个User 实体,这就是问题所在 - 我现在有两个具有相同主键值的用户实体。
我想知道是否应该在保存更改之前将 existingUser 实体从上下文中分离出来,还是有更好的方法?
感谢任何反馈。
谢谢。
【问题讨论】:
-
如果您只查询电子邮件匹配和 ID 匹配的记录数怎么办。如果结果为 0 则返回 false,否则返回 true。
-
@Serge 这是一个奇怪的评论。工作单元和通用存储库模式已成功用于全球 Web 应用程序。在开发 .NET 和 .NET Core 应用程序时,Pluralsight 和 Microsoft 都会教授此类模式。
-
@tcode
That's a strange comment.恰恰相反,将“通用存储库”(它实际上是一个 DAO)放在像 EF Core 这样的 ORM 之上是一种臭名昭著的反模式,会导致 ton i> 的问题。就在今天,我遇到了至少 3 个由此引起的问题。一个 DbContext已经是一个工作单元,一个 DbSet已经是一个存储库。现在我们不知道你的代码是做什么的。没有附加实体的代码。我们不知道UserAlreadyExists是什么,尽管我怀疑它会加载您要更新的实体,从而导致错误。 -
@PanagiotisKanavos 我相信我确实发布了“相关”代码和足够的文字描述。是的,我知道是什么导致了这个问题,但我正在就如何解决它征求其他意见,因为我不确定我提出的建议是最好的方法。我认为我们最好保留这个讨论,但是,阅读此内容不会造成伤害stackoverflow.blog/2018/04/26/…
标签: c# asp.net-core entity-framework-core dbcontext unit-of-work