2015-03-02 53 views
0

我正在從使用.Net4/EF 4.4到.Net4.5/EF 6.1升級WPF應用程序。升級後,我將使用DbContext(因爲ObjectContext沒有POCO生成器)。是否有可能在實體框架6中將ObjectSet轉換爲DbSet?

應用程序使用存儲庫/ UnitOfWork模式來訪問實體框架,在升級之前,我可以將ObjectSet.MergeOption設置爲OverwriteChanges(在存儲庫類中),但DbSet類沒有此功能。但是,我知道我可以通過使用IObjectContextAdapter從DbContext獲取ObjectSet。 (請參閱下面的代碼)。但似乎在創建的ObjectSet上設置MergeOption不會反射回DbSet。

所以我的問題是這樣的:有什麼辦法將ObjectSet轉換回DbSet(保存MergeOption設置)?

這是一些倉庫類:

public class SqlRepository<T> : IRepository<T> where T : class, IEntity 
{ 
    protected DbSet<T> dbSet; 

    public SqlRepository(DbContext context) 
    { 
     var objectContext = ((IObjectContextAdapter)context).ObjectContext; 
     var set = objectContext.CreateObjectSet<T>(); 
     set.MergeOption = MergeOption.OverwriteChanges; 


     dbSet = context.Set<T>(); 
//I would like to do something like this: dbSet = (DbSet)set; 


    } 
} 
+0

有一個POCO生成器:https://visualstudiogallery.msdn.microsoft。com/66612113-549c-4a9e-a14a-f629ceb3f89a – ErikEJ 2015-03-02 10:19:32

+0

@ErikEJ是的,我意識到這一點,但我不認爲它創建POCO,而是創建EntityObject派生類?當我使用它時,它只創建了xxModel.tt文件,而不像x4Model.Context.tt文件那樣在EF4.4版本的T4中創建。 – GHauan 2015-03-02 14:48:59

+0

對不起,你是對的...... – ErikEJ 2015-03-02 16:49:01

回答

0

雖然沒有直接回答你的問題,我想出了一個基於T4解決各地MergeOption不是在DbSet訪問的EF監督。從你的問題來看,這就是你正在尋找的東西?

在默認環境下,你必須用T4發電機等產生的東西:

public virtual DbSet<Person> Persons { get; set; } 
public virtual DbSet<Address> Addresses { get; set; } 

我的方法是編輯T4添加吸氣劑爲每個實體提供直接訪問的對象集作爲一個IQueryable:

public IQueryable<Person> GetPersons(MergeOption mergeOption = MergeOption.AppendOnly, bool useQueryImplentation = true) 
{ 
    return useQueryImplementation ? GetSet<Person>(mergeOption).QueryImplementation() : GetSet<Person>(mergeOption); 
} 

然後在鹼的DataContext

public class DataContextBase 
{ 

    /// <summary> 
    /// Gets or sets the forced MergeOption. When this is set all queries 
    /// generated using GetObjectSet will use this value 
    /// </summary> 
    public MergeOption? MergeOption { get; set; } 


/// <summary> 
/// Gets an ObjectSet of type T optionally providing a MergeOption. 
/// <remarks>Warning: if a DataContext.MergeOption is specified it will take precedence over the passed value</remarks> 
/// </summary> 
/// <typeparam name="TEntity">ObjectSet entity Type</typeparam> 
/// <param name="mergeOption">The MergeOption for the query (overriden by DataContext.MergeOption)</param> 
protected IQueryable<TEntity> GetObjectSet<TEntity>(MergeOption? mergeOption = null) where TEntity : class 
{ 
    var set = Context.CreateObjectSet<TEntity>(); 
    set.MergeOption = MergeOption ?? mergeOption ?? MergeOption.AppendOnly; 

    return set; 
} 

通過創建一個IQueryable一個默認的擴展方法如下,你可以選擇添加自己QueryImplementation的implenations爲每個表/類型,以便您的表的所有用戶獲得排序或包括等(不需要這部分要回答這個問題,但無論如何它是有用的)

因此,舉例來說,你可以添加以下調用GetPersons()

public static class CustomQueryImplentations 
{ 
     public static IQueryable<Person> QueryImplementation(this IQueryable<Person> source) 
     { 
      return source 
       .Include(r => r.Addresses) 
       .OrderByDescending(c => c.Name); 
     } 
    } 

最後時,始終包括地址:

//just load a simple list with no tracking (Fast!) 
var people = Database.GetPersons(MergeOption.NoTracking); 

//user wants to edit Person so now need Attached Tracked Person (Slow) 
var peson = Database.GetPersons(MergeOption.OverwriteChanges).FirstOrDefault(p => p.PersonID = 1); 

//user makes changes and on another machine sometime later user clicks refresh 
var people = Database.GetPersons(MergeOption.OverwriteChanges); 

或者你也可以(如我)喜歡寫東西使用現有的Get方法實體

Database.MergeOption = MergeOption.OverwriteChanges; 

刷新加載,但所有的一切都會覆蓋已添加實體

Database.MergeOption = null; 

一些需要注意的是如果您在進行更改之前加載AsNoTracking,則需要使用OverwriteChanges重新附加或可能更好的重新加載,以確保您擁有最新的實體。

+0

謝謝你的例子。當我得到時間時,我會更密切地關注它......自從我的帖子以來,我不得不轉向其他事情。我記得對於我來說,困難的事情之一是,我試圖升級的應用程序使用了一種非常通用的方法來處理EF Things(Repository/Uow),這使得很難利用EF的一些更具體的特性。但是,再次感謝您的建議。 – GHauan 2016-01-19 07:29:27