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

时间:2022-07-20 06:50:31

I'm using Entity Framework 5 with MySQL Database and just wanted to update a row attribute "user_loginstatus" between 0 and 1. The first time when I log in via client it updates just fine for the first attempt, after trying to update again it doesn't do anything with no exception.

我正在使用实体框架5与MySQL数据库,只是想在0和1之间更新行属性“user_loginstatus”。我第一次通过客户端登录时,在尝试再次更新后,第一次尝试更新就好了什么都不做,没有例外。

I log in like this:

我这样登录:

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...
    }
}

SetUserStatus Method in DataService Class

DataService类中的SetUserStatus方法

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 Method in DataService Class

DataService类中的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;
        }
    });
}

So "users" is my table from the database and "User" / "UserObj" my custom Object. With the Messenger (from MVVM Light) I just set via MainViewModel the Views, reset the unused ViewModels (ViewModel = new VieModel(...); or ViewModel = null;) and pass the current / logged in User Object.

所以“用户”是我的数据库表和“User”/“UserObj”我的自定义对象。使用Messenger(来自MVVM Light)我只需通过MainViewModel设置视图,重置未使用的ViewModel(ViewModel = new VieModel(...);或ViewModel = null;)并传递当前/登录的用户对象。

With the same strategy I just Logout like this

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

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"));
            });
        }
    }

So I can log in with my running Client so often I want, but the "user_loginStatus" only sets the changes the first login time to 1 and back to 0, but when I log out then and login back with the same user, it wont change it anymore. When I login (still same running Client) with another user it sets again the first time the "user_loginstatus" to 1 and back to 0 and then only again when I restart my Client..

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

What could I do wrong?

我该怎么办?

2 个解决方案

#1


0  

This is just basically from my comment regarding the original question:

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

I had similiar problems several times. Usually it is based on the fact that the entity you modified can't be validated properly and your dbContext fails without a proper exception because it still holds on to false entity. If this is the case you could circumvent this problem by using scoped contexts and embedding your data access operations in a using statement.

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

Alternatively you could try to explicitly tell EF that the entity has changes e.g.:

或者,您可以尝试明确告诉EF实体有变化,例如:

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

Regarding your other question:

关于你的另一个问题:

In theory you shouldn't have to tell EF explicitly that the entity's values have changed. Change tracking should do that automatically. The only exception i could think of, is when you try to modify an entity that is explicitly not tracked anymore. When you call _entities.Find(id) it will look in the context if it finds the object with the matching primary key value and load it. Since you already modified this object before, the context will simply get the old object you already modified to set the login status the first time.

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

This "old" object is probably not tracked anymore and you have to tell EF explicitly that it has changed, by changing it's state from attached to modified.

这个“旧”对象可能不再被跟踪,你必须通过将其状态从附加更改为已修改,明确告诉EF它已更改。

#2


0  

in LoginExecute() you have UserObj, but in LogoutCommand() you have CurrentUser. Is it OK?

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

#1


0  

This is just basically from my comment regarding the original question:

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

I had similiar problems several times. Usually it is based on the fact that the entity you modified can't be validated properly and your dbContext fails without a proper exception because it still holds on to false entity. If this is the case you could circumvent this problem by using scoped contexts and embedding your data access operations in a using statement.

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

Alternatively you could try to explicitly tell EF that the entity has changes e.g.:

或者,您可以尝试明确告诉EF实体有变化,例如:

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

Regarding your other question:

关于你的另一个问题:

In theory you shouldn't have to tell EF explicitly that the entity's values have changed. Change tracking should do that automatically. The only exception i could think of, is when you try to modify an entity that is explicitly not tracked anymore. When you call _entities.Find(id) it will look in the context if it finds the object with the matching primary key value and load it. Since you already modified this object before, the context will simply get the old object you already modified to set the login status the first time.

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

This "old" object is probably not tracked anymore and you have to tell EF explicitly that it has changed, by changing it's state from attached to modified.

这个“旧”对象可能不再被跟踪,你必须通过将其状态从附加更改为已修改,明确告诉EF它已更改。

#2


0  

in LoginExecute() you have UserObj, but in LogoutCommand() you have CurrentUser. Is it OK?

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