Entity framework 4 EF4更新导航属性一个实体对象不能被多个IEntityChangeTracker实例引用

Entity framework 4 EF4更新导航属性一个实体对象不能被多个IEntityChangeTracker实例引用,entity-framework-4,navigation,Entity Framework 4,Navigation,我正在尝试实现一个比方说更改我的帐户电子邮件地址的功能 我想保留R_EmailAddressHistory表中所有用户电子邮件的备份 下面是我的一些项目代码 public bool ChangeEmailAddress(string username, string newEmailAddress, string callbackUrl) { DateTime currentUtcTime = DateTime.UtcNow; R_User currentUser = Use

我正在尝试实现一个比方说更改我的帐户电子邮件地址的功能

我想保留R_EmailAddressHistory表中所有用户电子邮件的备份

下面是我的一些项目代码

public bool ChangeEmailAddress(string username, string newEmailAddress,  string callbackUrl)
{
    DateTime currentUtcTime = DateTime.UtcNow;

    R_User currentUser = UserRepo.GetSingle(whereCondition: w=>w.Username == username);
    currentUser.UpdateDate = currentUtcTime;

    if (currentUser.HasPendingNewEmail)
    {
        R_EmailAddressHistory currentPendingRequest = EmailHistoRepo.GetSingle(whereCondition: w => w.StatusID == (int)Reno.Common.Enums.RecordStatus.Pending && w.R_User.GId == currentUser.GId);
        currentPendingRequest.NewEmail = newEmailAddress;
        currentPendingRequest.UpdateDate = currentUtcTime;

        EmailHistoRepo.Update(currentPendingRequest);
    }
    else
    {
        currentUser.HasPendingNewEmail = true;

        R_EmailAddressHistory newEmail = new R_EmailAddressHistory();
        newEmail.UserId = currentUser.GId;
        newEmail.R_User = currentUser;
        newEmail.NewEmail = newEmailAddress;
        newEmail.InsertDate = currentUtcTime;
        newEmail.StatusID = (int) Reno.Common.Enums.RecordStatus.Pending;
        currentUser.R_EmailAddressHistory.Add(newEmail);
    }

    IdentityResult idtResult = UserRepo.Update(currentUser);

    if(idtResult == IdentityResult.Succeeded)
    {
        //Send notification to current email address for validation before proceeding change email process
        bool sendResult = Communication.EmailService.SendChangeEmailValidation(username,currentUser.Email, newEmailAddress, callbackUrl);
        return sendResult;
    }
    else
    {
        return false;
    }
}
前面的方法用于更改电子邮件地址。我的每个表R_User和EmailAddressHistory都有存储库UserRepo和emailhistorrepo。实现相同的IRepositoryBase类,下面是更新方法

public IdentityResult Update(T entity)
{
    try
    {
        if (_currentContext.DbContext.Entry(entity).State == EntityState.Detached)
        {
            _currentContext.DbContext.Set<T>().Attach(entity);
        }

        _currentContext.DbContext.Entry(entity).State = EntityState.Modified;

        return IdentityResult.Succeeded;
    }
    catch
    {
        return IdentityResult.Failed;
    }
}

您的当前用户在更新电子邮件地址之前已被修改。首先将更改保存到currentUser

大概是这样的:

R_User currentUser = UserRepo.GetSingle(whereCondition: w=>w.Username == username);
currentUser.UpdateDate = currentUtcTime;

bool pendingNewEmail = currentUser.HasPendingNewEmail;
 UserRepo.Update(currentUser);

if (pendingNewEmail)
{
    R_EmailAddressHistory currentPendingRequest = EmailHistoRepo.GetSingle(whereCondition: w => w.StatusID == (int)Reno.Common.Enums.RecordStatus.Pending && w.R_User.GId == currentUser.GId);
    currentPendingRequest.NewEmail = newEmailAddress;
    currentPendingRequest.UpdateDate = currentUtcTime;

    EmailHistoRepo.Update(currentPendingRequest);
}
else

我终于找到了答案。问题是当我第一次让用户排队时

 R_User currentUser = UserRepo.GetSingle(whereCondition: w=>w.Username == username);
currentUser变量保存其所有R_EmailAddressHistory的引用。 然后,我第二次查询DB以获取挂起的电子邮件更改请求,或者键入R_EmailAddressHistory以修改其新电子邮件及其更新日期,在第行中

R_EmailAddressHistory currentPendingRequest = EmailHistoRepo.GetSingle(whereCondition: w => w.StatusID == (int)Reno.Common.Enums.RecordStatus.Pending && w.R_User.GId == currentUser.GId);
            currentPendingRequest.NewEmail = newEmailAddress;
            currentPendingRequest.UpdateDate = currentUtcTime;
但te last代码仅更新currentPendingRequest,而currentUser.R_EmailAddressHistory中相同对象的另一个引用未更新,并且已被上下文跟踪。因此,通过对新实例EmailHistorRepo.UpdatecurrentPendingRequest进行更新,代码失败:如果在两个位置引用了相同的对象

因此,解决方案是我唯一修改的:

            R_User currentUser = UserRepo.GetSingle(whereCondition: w=>w.Username == username);
        currentUser.UpdateDate = currentUtcTime;

        if (currentUser.HasPendingNewEmail)
        {
            R_EmailAddressHistory currentPendingRequest = currentUser.R_EmailAddressHistory.Where(h => h.StatusID == (int)Reno.Common.Enums.RecordStatus.Pending).First(); // EmailHistoRepo.GetSingle(whereCondition: w => w.StatusID == (int)Reno.Common.Enums.RecordStatus.Pending && w.R_User.GId == currentUser.GId);
            currentPendingRequest.NewEmail = newEmailAddress;
            currentPendingRequest.UpdateDate = currentUtcTime;

        }

我决定修改currentUser变量中的实例。

旁注:存储库不应返回IdentityResult,它不应以任何方式了解ASP.Net。单一责任原则。谢谢Gert,我会做出改变Hi Leondelaw,问题是我实际上也在使用MVC4和unitoOfWork模式。首次在控制器中查询数据库时,我的UOW是初始化的,它在Global.aspx中的我的应用程序\ EndRequest方法上提交
            R_User currentUser = UserRepo.GetSingle(whereCondition: w=>w.Username == username);
        currentUser.UpdateDate = currentUtcTime;

        if (currentUser.HasPendingNewEmail)
        {
            R_EmailAddressHistory currentPendingRequest = currentUser.R_EmailAddressHistory.Where(h => h.StatusID == (int)Reno.Common.Enums.RecordStatus.Pending).First(); // EmailHistoRepo.GetSingle(whereCondition: w => w.StatusID == (int)Reno.Common.Enums.RecordStatus.Pending && w.R_User.GId == currentUser.GId);
            currentPendingRequest.NewEmail = newEmailAddress;
            currentPendingRequest.UpdateDate = currentUtcTime;

        }