实体框架 5 更新对每个对象/行仅工作一次

本文关键字:工作 一次 更新 框架 对象 实体 | 更新日期: 2023-09-27 18:34:42

我正在使用带有MySQL数据库的实体框架5,只想更新0到1之间的行属性"user_loginstatus"。当我第一次通过客户端登录时,它第一次尝试更新就很好,尝试再次更新后,它没有做任何事情,没有例外。

我像这样登录:

public async void LoginExecute()
{
    // Checking Connection before etc...
    if (await _dataService.IsLoginDataValidTask(UserObj.Username, md5))
    {
        Trace.WriteLine("LoginCommand Execute: Eingeloggt");
        UserObj = await _dataService.GetUserDataTask(UserObj.Username);
        await _dataService.SetUserStatusTask(UserObj.Id, 1);
        await _dataService.WriteLog(UserObj.Id, "login", "Programm", GetLocalAdress());
        Messenger.Default.Send(UserObj);
        Messenger.Default.Send(new NotificationMessage("GoToMenuPage"));
    }
    else
    {
        // Error Stuff...
    }
}

数据服务类中的设置用户状态方法

public Task SetUserStatusTask(int id, int status)
{
    return Task.Factory.StartNew(() =>
    {
        try
        {
            var user = _entities.users.Find(id);
            user.user_loginstatus = status;
            _entities.SaveChanges();
        }
        catch (Exception ex)
        {
            Trace.WriteLine("DataService SetUserStatusTask: " + ex.Message);
        }
    });
}

数据服务类中的 GetUserData 方法

public Task<User> GetUserDataTask(string username)
{
    return Task.Factory.StartNew(() =>
    {
        try
        {
            var user = from us in _entities.users
                       where us.user_name.Equals(username)
                       select new User
                       {
                           Id = us.user_id,
                           Username = us.user_name,
                           FirstName = us.user_firstname,
                           LastName = us.user_lastname,
                           Gender = us.user_gender,
                           Email = us.user_mail,
                           Group = us.user_usergroup,
                           Avatar = us.user_avatar,
                           LoginStatus = 1
                      };
            return user.FirstOrDefault();
        }
        catch (Exception ex)
        {
            Trace.WriteLine("DataService GetUserDataTask: " + ex);
            return null;
        }
    });
}

因此,我的表"users"数据库中,"User" / "UserObj"我的自定义对象。使用Messenger(来自 MVVM Light(,我只需通过 MainViewModel 设置视图,重置未使用的视图模型(ViewModel = new VieModel(...);ViewModel = null; (并传递当前/登录的用户对象。

使用相同的策略,我只是像这样注销

public ICommand LogoutCommand
    {
        get
        {
            return new RelayCommand(async () =>
            {
                await _dataService.SetUserStatusTask(CurrentUser.Id, 0);
                if(CurrentUser.Id > 0 && IsLoggedIn)
                    await _dataService.WriteLog(CurrentUser.Id, "logout", "Programm", GetLocalAdress());
                IsLoggedIn = false;
                CurrentUser = new User();
                Messenger.Default.Send(new NotificationMessage("GoToLoginPage"));
            });
        }
    }

因此,我可以经常使用正在运行的客户端登录,但是"user_loginStatus"仅将首次登录时间的更改设置为 1 并重新设置为 0,但是当我注销并使用同一用户重新登录时,它不会再更改它了。当我使用另一个用户登录(仍然相同的正在运行的客户端(时,它第一次将"user_loginstatus"再次设置为 1 并返回到 0,然后仅在我重新启动客户端时再次设置。

我能做错什么?

实体框架 5 更新对每个对象/行仅工作一次

这基本上来自我对原始问题的评论:

我有几次类似的问题。通常,它基于这样一个事实,即您无法正确验证您修改的实体,并且您的 dbContext 在没有适当异常的情况下失败,因为它仍然保留了错误的实体。如果是这种情况,您可以通过使用作用域上下文并将数据访问操作嵌入到 using 语句中来规避此问题。

或者,您可以尝试显式告诉 EF 实体已更改,例如:

_entities.Entry(user).State = EntityState.Modified;

关于你的另一个问题:

理论上,不必显式告知 EF 实体的值已更改。更改跟踪应自动执行此操作。我能想到的唯一例外是当您尝试修改明确不再跟踪的实体时。当你打电话给_entities时。Find(id( 如果它找到具有匹配主键值的对象并加载它,它将在上下文中查找。由于您之前已经修改了此对象,因此上下文将仅获取您已经修改的旧对象,以便在第一次设置登录状态。

此"旧"对象可能不再被跟踪,你必须通过将它的状态从"附加"更改为"已修改"来明确告诉 EF 它已更改。

在 LoginExecute(( 中你有 UserObj,但在 LogoutCommand(( 中有 CurrentUser。可以吗?