WPF和EF6将模型实体标记为具有更改

时间:2013-11-22 18:24:08

标签: .net wpf vb.net entity-framework entity-framework-6

背景 我有一个wpf 4.5应用程序,它首先使用MVVM(MVVM-Light)和Enitity Framework 6 db构建。

我有几个视图模型,其列表/详细信息设置为列表框中的对象列表,以及显示并允许用户编辑列表框的选定记录的详细信息网格。我在网格顶部有一个SAVE和UNDO按钮,当我对所选记录的基础模型实体进行更改时,我想“启用”。

我能够做到这一点,但我当前解决方案的性能非常糟糕,我需要一种新策略来检测模型中的变化。

我现在拥有的东西:

我有一个CanSaveExecute方法,它是ICommand对象的CanExecute回调。在该方法中,我查询EF dbContext ChangeTracker实体以查看是否存在我所需类型的任何对象。

 Try
    If _Selection IsNot Nothing AndAlso _Selection.HasErrors = False Then
         Return (From entry In Context.ChangeTracker.Entries(Of job)() Where entry.Entity.idJob = _Selection.idJob And entry.State = EntityState.Modified Select entry).Count
    Else
         Return False
    End If
 Catch ex As Exception
    Return False
 End Try

问题是此更改跟踪器条目的查询正在破坏UI性能。它会导致用户输入严重滞后。

我的问题:

有人有更好的策略来检测使用Entity Framework 6的CanExecute方法中的更改吗?最好不要更改T4代码(但我觉得这是我最终会在哪里)。


更多细节:

以下是我的模型设置方式。 EF6为我生成一个简单的实体类,看起来像这个(我删除了很多属性以保持简单为例)

Imports System
Imports System.Collections.Generic

Partial Public Class job
    Public Property idJob As Integer
    Public Property idLinkedJob As Nullable(Of Integer)
    Public Property idStatus As Byte
    Public Property idEstimate As Nullable(Of Integer)
    Public Property chrTitle As String

    Public Overridable Property alerts As ICollection(Of alert) = New HashSet(Of alert)
    Public Overridable Property client As client
End Class

我用另一个部分类扩展该类以添加数据验证规则,例如(再次,简化为例)

Partial Public Class job
    Inherits ValidationBase

#Region "PROPERTIES"
    Public Property HasChanges As Boolean = False
#End Region

#Region "CONSTRUCTORS"
    Public Sub New()
        ''default values
        Me.FTC_Type = 4
        Me.dtCreated = Now
        Me.dtUpdated = Now
        'HasChanges = False
    End Sub

    Public ReadOnly Property DisplayPath
        Get
            Return "W" + idJob.ToString + ": " + chrTitle + " - " + client.chrCompany
        End Get
    End Property
#End Region

#Region "VALIDATION FUNCTIONS"

    Public Overrides Function Validate(validationContext As ComponentModel.DataAnnotations.ValidationContext) As IEnumerable(Of ComponentModel.DataAnnotations.ValidationResult)
        Return MyBase.Validate(validationContext)
        PropertyValitaion(True)
    End Function

    Public Sub PropertyValitaion(bAllProperties As Boolean, Optional sProperty As String = "")
        'initialize validation helper

        If bAllProperties OrElse sProperty = "chrTitle" Then
            If String.IsNullOrEmpty(chrTitle) Then
                AddError("chrTitle", "You must enter a Job Title")
            Else
                RemoveError("chrTitle")
            End If
        End If
        If bAllProperties OrElse sProperty = "idClient" Then
            If idClient < 1 Then
                AddError("idClient", "You must select a job client")
            Else
                RemoveError("idClient")
            End If
        End If

        If String.IsNullOrEmpty(sProperty) = False Then
            OnPropertyChanged(sProperty)
        End If

    End Sub
#End Region
End Class

没有解决方案:

所以在与它斗争了一天后,我认为@Shoe是对的。结果证明这个功能太多了。我永远无法调用更改跟踪器,以免导致UI延迟。

2 个答案:

答案 0 :(得分:0)

EF6有一个内置函数,用于检查上下文是否包含任何更改:DbChangeTracker.HasChanges,请参阅http://msdn.microsoft.com/en-us/data/jj574253

对我来说,性能比你用过的类似的查询更好。 但是,我也在CanExecute上使用它,它仍然导致UI滞后。

编辑:

我找到了一个更好的解决方案:使用代理进行变更检测

首先确保模型的所有属性都是虚拟的。集合应映射为iCollection。这样,代理对象将在何时创建 Context.Configuration.ProxyCreationEnable = true

要检测更改,您可以使用:

Context.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EtityState.Modified | EntityState.Unchanged).Any()

因为这不需要快照比较,所以它比调用默认的DbChangeTracker.HasChanges要快得多,这将导致DetectChanges()调用。请记住,如果代理生成失败,例如因为不使用虚拟,则不会检测到更改。另请参阅https://msdn.microsoft.com/en-us/library/vstudio/dd468057%28v=vs.100%29.aspx

答案 1 :(得分:0)

我只是没有看到MS对Entity Framework所做的更改有任何好处。这些类不再支持更改跟踪和查询,如果有更改比使用dbcontext慢很多倍。我希望他们能够更好地记录所有这些变化,这样我就不会浪费那么多时间来让它发挥作用。

顺便说一句,如果我使用一个viewmodel,让我说我有60个字段的产品实体。这些字段的更改如何传播回模型?