背景 我有一个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延迟。
答案 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个字段的产品实体。这些字段的更改如何传播回模型?