首页 > 解决方案 > 异常实体已被跟踪

问题描述

我在跟踪健全模型时遇到错误,但我不知道如何访问模型并保存更改。错误如下所示:

        System.InvalidOperationException: 'The instance of entity type 'UserMetaData' cannot be tracked 
    because another instance with the same key value for {'UserId'} is already being tracked. When attaching
     existing entities, ensure that only one entity instance with a given key value is attached. Consider 
    using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the conflicting key values.'

使我的网站崩溃的代码是这样的:

public IActionResult ConsentForm(string holder)
{
    var id = _httpContextAccessor.HttpContext.Session.GetString("UserId");
    var userId = new Guid(id);
    var userMetaInfo = _elearnContext.UserMetaData.Where(u => u.UserId == userId).SingleOrDefault();


    UserMetaData userMetaData = new UserMetaData
    {
        UserId = userId,
        Consent = userMetaInfo.Consent,
        Location = "",
        CanChangePassword = true
    };
    _elearnContext.UserMetaData.Add(userMetaData);// crashes here 
    _elearnContext.SaveChanges();
    return RedirectToAction("LogOn", "Account");
    // return View("~/Views/Home/ConsentForm.cshtml", ConsentData);
}

我认为问题在于,在调用此函数之前,我在前一个函数中使用了相同的访问权限,如下所示:

public IActionResult RedirectToConsentForm(string controllerName, string actionName)
{

    var Id = _httpContextAccessor.HttpContext.Session.GetString("UserId");
    var UserId = new Guid(Id);
    var UserMetaInfo = _elearnContext.UserMetaData.Where(u => u.UserId == UserId).SingleOrDefault();


    if (UserMetaInfo.Consent == true)
    {
        return RedirectToAction("ConsentForm", "Account");

    }
    else
    {
        return RedirectToAction(controllerName, actionName);
    }

}

如果有人有任何想法,请告诉我。

标签: c#asp.net-mvcasp.net-core

解决方案


在这种情况下,您的方案实际上是更新元数据(如果存在),否则添加一个新元数据。它崩溃是因为在查询元数据后,它被跟踪(AsNoTracking未使用)。然后将该跟踪的实体添加到上下文中并导致错误。应该是这样的:

var userMetaInfo = _elearnContext.UserMetaData.SingleOrDefault(u => u.UserId == userId) ?? new UserMetaData();
if(userMetaInfo.UserId == 0){
  //set the consent only at the time creating a new metadata
  userMetaInfo.Location = someLocation;
  userMetaInfo.CanChangePassword = true;
  //add the new entity to the context (mark it as added)
  _elearnContext.UserMetaData.Add(userMetaInfo);
}
//now set this to update the consent which should be true
//because this code is run only after the user accepted (redirected from another action)
userMetaInfo.Consent = true;

//finally save the changes
_elearnContext.SaveChanges();

注意我不确定你设置了什么Location(以及何时更新它)。所以这取决于你的逻辑。但看起来在上面的代码中,您唯一要更新的是Consent属性,而且它必须是true. 尽管我们检查UserId是否正在创建新的元数据,但我相信当时,元数据可能已经创建(在其他地方)。然而,这是我们在这种情况下处理它的一般逻辑(类似于仅在没有现有数据时添加实体,否则更新获取和跟踪实体的属性)。


推荐阅读