是否可以在实体框架6中将ObjectSet转换为DbSet?

时间:2015-03-02 09:43:22

标签: entity-framework dbset objectset

我正在努力将WPF应用程序从使用.Net4 / EF 4.4升级到.Net4.5 / EF 6.1。升级后我将使用DbContext(因为没有用于ObjectContext的POCO生成器)。

应用程序使用Repository / UnitOfWork模式访问Entity Framework,在升级之前,我可以将ObjectSet.MergeOption设置为OverwriteChanges(在repository-class中),但DbSet-class没有此功能。但是,我知道我可以通过使用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;


    }
}

1 个答案:

答案 0 :(得分:0)

虽然不能直接回答您的问题,但我已经提出了一个基于T4的解决方案,以解决围绕MergeOption的EF监督无法在DbSet中访问的问题。从您的问题看来,这是您在寻找什么?

在默认上下文中,您有T4生成器生成的内容,如:

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

我的方法是编辑T4,为每个实体添加Getters,提供直接访问ObjectSet作为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创建默认的Extension方法,您可以选择为每个表/类型添加自己的QueryImplementation实现,以便表的所有用户都可以进行排序或包含等。(此部分不需要回答问题,但无论如何它是有用的)

例如,您可以在调用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);

或者你可以(像我一样)写一些像

这样的东西
Database.MergeOption = MergeOption.OverwriteChanges;

使用现有的Get方法刷新实体的负载,但现在将覆盖附加的实体

Database.MergeOption = null;

需要注意的是,如果您在进行更改之前加载AsNoTracking,则需要重新附加或者最好使用OverwriteChanges重新加载以确保您拥有最新的实体。