2015-03-02 93 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