WPF 实体框架刷新一个上下文实体

Posted

技术标签:

【中文标题】WPF 实体框架刷新一个上下文实体【英文标题】:WPF Entity Framework refresh one context entity 【发布时间】:2017-02-24 10:50:24 【问题描述】:

我有一个简单的 MVVM WPF 应用程序,它带有数据库优先的 EF dbContext(在我的应用程序中是 Global.Database),它在我的应用程序中长期存在。 我有一个带有ItemsSource 的列表框的窗口,该列表框绑定到名为Clients 的viewmodel 属性,这是我的dbmodel ClientObservableCollection

此列表框的SelectedItem 绑定到名为SelectedClient 的视图模型属性。

Client 实体类中有一个名为last_status 的字段,它是我数据库中的一个简单整数。

所以,在我看来,当我从列表框中选择客户端时,绑定到 SelectedClient 的last_status 的标签应该显示last_status 的值。

我在视图模型中添加了一个按钮和一个刷新命令。我想要的是:当我在我的数据库中为客户端手动更改last_status 并在我的视图中按刷新按钮时,标签的内容应该会改变。但我完全不知道如何实现这一目标。这是我的视图模型代码的一部分(我使用 Catel,但对于这种情况并不重要):

public ClientManagerWindowViewModel()
    

       RefreshClientInfoCommand = new Command(OnRefreshClientInfoCommandExecute);

       Clients = new ObservableCollection<Client>();
       RefreshClients();
    

public ObservableCollection<Client> Clients
    
        get  return GetValue<ObservableCollection<Client>>(ClientsProperty); 
        set  SetValue(ClientsProperty, value); 
    

    public static readonly PropertyData ClientsProperty = RegisterProperty("Clients", typeof(ObservableCollection<Client>));

public Client SelectedClient
    
        get
        return GetValue<Client>(SelectedClientProperty);
        set
        
            SetValue(SelectedClientProperty, value);
        
    

    public static readonly PropertyData SelectedClientProperty = RegisterProperty("SelectedClient", typeof(Client));


//here is my refresh button command handler:

 public Command RefreshClientInfoCommand  get; private set; 

 private void OnRefreshClientInfoCommandExecute()
 
     RefreshClientInfo(SelectedClient);
 

//and here is my "logic" for working with dbcontext:

private void RefreshClients()
    
        var qry = (from c in Global.Database.Clients where c.client_id != 1 select c).ToList();
        Clients = new ObservableCollection<Client>(qry);
    

private void RefreshClientInfo(Client client)
    
        Global.Database.Entry(client).Reload();
    

我的列表框 XAML:

<ListBox
                    x:Name="ClientsListBox"
                    Grid.Row="1"
                    Margin="5"
                    DisplayMemberPath="fullDomainName"
                    IsSynchronizedWithCurrentItem="True"
                    ItemsSource="Binding Clients"
                    SelectedItem="Binding SelectedClient" />

我的标签的 XAML:

<Label Margin="5" Content="Binding SelectedClient.last_status" />

对于一个按钮:

<Button Command="Binding RefreshClientInfoCommand" Content="↻"/>

现在,当我在数据库中手动更改客户的 last_status 值并按下刷新按钮时,什么也没有发生。但是当我在列表框中选择另一个客户端然后返回到所需的客户端时 - 标签内容正确更新。我知道,也许我错过了一些非常愚蠢和简单的事情,但我无法弄清楚到底是什么。也许我需要在我的按钮命令处理程序中强制更改SelectedClient,或者以某种方式调用SelectedClients setter... 请帮我。非常感谢。

【问题讨论】:

你也应该刷新绑定。 【参考方案1】:

好吧,我发现我的代码出了什么问题。

我的数据绑定设置为SelectedClient.last_status。由于某种原因,它没有按我的预期工作。所以我创建了一个名为 LastStatus 的新视图模型属性并修改了我的 RefreshClientInfo:

 private void RefreshClientInfo(Client client)
    
        Global.Database.Entry(client).Reload();
        LastStatus = client.last_status;
        SetValue(SelectedClientProperty, client);
    

并将标签绑定到这个新属性。现在一切正常。

【讨论】:

【参考方案2】:

您需要将 SelectedClient 属性设置为您从 EF 查询返回的新 Client 对象。

您可以通过在查询数据库之前存储当前所选客户端的client_id 来做到这一点,然后选择具有此特定client_id 的新Client 对象。

试试这个:

private void RefreshClients()

    int? currentlySelectedClientId = (SelectedClient != null) ? SelectedClient.client_id : default(int?);
    var qry = (from c in Global.Database.Clients where c.client_id != 1 select c).ToList();
    Clients = new ObservableCollection<Client>(qry);
    if (currentlySelectedClientId.HasValue)
        SelectedClient = Clients.FirstOrDefault(x => x.client_id = currentlySelectedClientId.Value);

编辑:确保从数据库中获取更新的记录:

private void RefreshClientInfo(Client client)

    var newClient = (from c in Global.Database.Clients where c.client_id == client.client_id select c).ToList();
    SetValue(SelectedClientProperty, newClient[0]);

【讨论】:

抱歉,我看不出它对我有什么帮助——我不想刷新所有客户端,我只想刷新一个。我通常要求的功能是RefreshClientInfo(Client client),而不是RefreshClients()。但也许我不明白。 更新后需要从数据库中重新获取客户端。查看我的编辑。 当我按下按钮时仍然不刷新:(当我在列表框中更改选定的客户端并返回时它会刷新。 您需要确保从数据库中获取更新的项目,并且您正在设置属性并为其引发 PropertyChanged 事件。查看我的编辑。 好吧,当我注释掉 Global.Database.Entry(client).Reload 并从编辑中放入您的代码时,它现在完全停止工作,并且没有通过按钮刷新下界,也没有选择另一个客户端并返回。

以上是关于WPF 实体框架刷新一个上下文实体的主要内容,如果未能解决你的问题,请参考以下文章

实体框架 + SQL Server Compact + WPF/WinForms = 缓慢的 UI?

如何刷新实体框架核心 DBContext?

实体框架和多线程

在运行时将实体对象添加到 LINQ-to-SQL 数据上下文 - SQL、C#(WPF)

实体框架分离实体和相关实体消失

当我从未将实体添加到上下文时,实体框架错误地保存了它