我正在編寫一個WPF應用程序,使用實體框架4作爲ORM的MVVM設計。我的視圖模型中有集合屬性,它將包含從EF4返回的實體集合,作爲IEnumerable<T>
集合,以響應業務層提交的查詢。實體框架4和WPF
我本來希望簡單地將IEnumerable<T>
結果集換成ObservableCollection<T>
。但是,我發現自己在我的存儲庫中編寫變更跟蹤代碼,或者維護已更改對象的影集,只是爲了保持視圖模型和持久層同步。每次將實體添加到視圖模型中的集合中時,我都必須前往我的存儲庫以將其添加到EF4 ObjectSet中。我必須做更新和刪除相同的事情。
爲了簡化工作,我從CodePlex(http://waf.codeplex.com/)上的WPF應用程序框架項目借了一個EdmObservableCollection<T>
類。該課程包含一個參考EF4 ObjectContext
的ObservableCollection<T>
,以便可以在更新集合時更新OC。我已經重印了下面的EdmObservableCollection
課程。該類運行得非常好,但它有一些代碼味道,因爲我最終在我的視圖模型中引用了EF4。
這裏是我的問題:在WPF應用程序中,保持EF4實體集合與其對象上下文同步的常用方法是什麼? EdmObservableCollection是一個合適的方法,還是有更好的方法?我在使用EF4時缺少一些基本的東西嗎?謝謝你的幫助。
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data.Objects;
using System.Linq;
namespace Ef4Sqlce4Demo.ViewModel.BaseClasses
{
/// <summary>
/// An ObservableCollection for Entity Framework 4 entity collections.
/// </summary>
/// <typeparam name="T">The type of EF4 entity served.</typeparam>
/// <remarks>Developed from WPF Application Framework (WAF) http://waf.codeplex.com/</remarks>
public class EdmObservableCollection<T> : ObservableCollection<T>
{
#region Fields
// Member variables
private readonly string m_EntitySetName;
private readonly ObjectContext m_ObjectContext;
#endregion
#region Constructors
/// <summary>
/// Creates a new EDM Observable Collection and populates it with a list of items.
/// </summary>
/// <param name="objectContext">The EF4 ObjectContext that will manage the collection.</param>
/// <param name="entitySetName">The name of the entity set in the EDM.</param>
/// <param name="items">The items to be inserted into the collection.</param>
public EdmObservableCollection(ObjectContext objectContext, string entitySetName, IEnumerable<T> items)
: base(items ?? new T[] {})
{
if (objectContext == null)
{
throw new ArgumentNullException("objectContext");
}
if (entitySetName == null)
{
throw new ArgumentNullException("entitySetName");
}
m_ObjectContext = objectContext;
m_EntitySetName = entitySetName;
}
/// <summary>
/// Creates an empty EDM Observable Collection that has an ObjectContext.
/// </summary>
/// <param name="objectContext">The EF4 ObjectContext that will manage the collection.</param>
/// <param name="entitySetName">The name of the entity set in the EDM.</param>
public EdmObservableCollection(ObjectContext objectContext, string entitySetName)
: this(objectContext, entitySetName, null)
{
}
/// <summary>
/// Creates an empty EDM Observable Collection, with no ObjectContext.
/// </summary>
/// <remarks>
/// We use this constructor to create a placeholder collection before we have an
/// ObjectContext to work with. This state occurs when the program is first launched,
/// before a file is open. We need to initialize collections in the application's
/// ViewModels, so that the MainWindow can get Note and Tag counts, which are zero.
/// </remarks>
public EdmObservableCollection()
{
}
#endregion
#region Method Overrides
protected override void InsertItem(int index, T item)
{
base.InsertItem(index, item);
m_ObjectContext.AddObject(m_EntitySetName, item);
}
protected override void RemoveItem(int index)
{
T itemToDelete = this[index];
base.RemoveItem(index);
m_ObjectContext.DeleteObject(itemToDelete);
}
protected override void ClearItems()
{
T[] itemsToDelete = this.ToArray();
base.ClearItems();
foreach (T item in itemsToDelete)
{
m_ObjectContext.DeleteObject(item);
}
}
protected override void SetItem(int index, T item)
{
T itemToReplace = this[index];
base.SetItem(index, item);
m_ObjectContext.DeleteObject(itemToReplace);
m_ObjectContext.AddObject(m_EntitySetName, item);
}
#endregion
#region Public Methods
/// <summary>
/// Adds an object to the end of the collection.
/// </summary>
/// <param name="item">The object to be added to the end of the collection.</param>
public new void Add(T item)
{
InsertItem(Count, item);
}
/// <summary>
/// Removes all elements from the collection.
/// </summary>
/// <param name="clearFromContext">Whether the items should also be deleted from the ObjectContext.</param>
public void Clear(bool clearFromContext)
{
if (clearFromContext)
{
foreach (T item in Items)
{
m_ObjectContext.DeleteObject(item);
}
}
base.Clear();
}
/// <summary>
/// Inserts an element into the collection at the specified index.
/// </summary>
/// <param name="index">The zero-based index at which item should be inserted.</param>
/// <param name="item">The object to insert.</param>
public new void Insert(int index, T item)
{
base.Insert(index, item);
m_ObjectContext.AddObject(m_EntitySetName, item);
}
/// <summary>
/// Updates the ObjectContext for changes to the collection.
/// </summary>
public void Refresh()
{
m_ObjectContext.SaveChanges();
}
/// <summary>
/// Removes the first occurrence of a specific object from the collection.
/// </summary>
/// <param name="item">The object to remove from the collection.</param>
public new void Remove(T item)
{
base.Remove(item);
m_ObjectContext.DeleteObject(item);
}
#endregion
}
}
有趣和周到的點;從我+1。我看到一些不同的問題。具體來說,我做了大量的數據和業務規則驗證。我使用視圖模型中的CollectionChanging事件來調用服務方法來進行驗證。如果驗證失敗,服務方法將取消操作並回調到視圖以顯示相應的錯誤消息。 – 2011-03-25 23:22:02
@David Veeneman:我不知道這個事件,有趣!它在WPF中可用嗎?我只是在搜索,只能在Windows窗體命名空間中找到它。 – Slauma 2011-03-25 23:35:56
糟糕 - 這是我在另一個版本的EdmObservableCollection上實現的事件。很容易做 - 聲明事件參數以通過操作(添加,更新,刪除),受影響的對象以及取消標誌(讀/寫)。在調用基類之前,在每個方法中引發事件並影響集合,如果Cancel設置爲true,則退出。我將就此主題編寫一篇CodeProject文章,並將在該代碼中包含該事件。謝謝你的收穫! – 2011-03-26 18:34:18