使用IQueryable <tentity>代替DbSet <tentity>问题</tentity> </tentity>

时间:2011-08-21 15:56:35

标签: c#-4.0 entity-framework-4 iqueryable dbcontext

我偶然发现了下一个问题......我有数据库上下文:

// For support unit testing... 
public interface IDbContext : IDisposable
{
   IQueryable<Hardware> Hardwares { get; }
   IQueryable<ProviderHardware> ProviderHardwares { get; }
}

// Real DbContext (EF 4.0, Code First)
public class PrimaryDbContext : DbContext, IDbContext
{
   public DbSet<Hardware> Hardwares { get; set; }
   public DbSet<ProviderHardware> ProviderHardwares { get; set; }

   IQueryable<Hardware> IDbContext.Hardwares
     { get { return Hardwares; } }
   IQueryable<ProviderHardware> IDbContext.ProviderHardwares
     { get { return ProviderHardwares; } } 
   ...
}

我尝试获取所有硬件,这些硬件在ProviderHardwares表中不存在:

var hardwaresRemoved = db.Hardwares.Where(i => (i.IsAvailable == true) &&
   (db.ProviderHardwares.Count(j => j.Article == i.Article) == 0)).ToList();

如果我严格使用PrimaryDbContext,例如“PrimaryDbContext db = new PrimaryDbContext();”一切正常。但如果我隐式使用它“IDbContext db = new PrimaryDbContext();”我得到一个例外:

  

无法创建类型的常量值   'ConfiguratorMvcApplication.DomainModels.ProviderHardware'。只要   支持原始类型(例如Int32,String和Guid')   这个背景。

总结一下,我无法替换IQueryable上的DbSet。在这种情况下我如何使用单元测试?我希望有人已经解决了这个问题...... 非常感谢!

2 个答案:

答案 0 :(得分:1)

我最终为每个DbSet提供了两个属性:一个是IQueryable类型,另一个是DbSet类型。 IQueryable属性在接口中定义,它将调用中继到具体实现(类型为DbSet的属性),如下所示:

// Exists in the interface
public IQueryable<AccountContact> AccountContacts
{ 
    get
    {
        return DbAccountContacts;
    }
    set
    {
        DbAccountContacts = (DbSet<AccountContact>)value; 
    }
}

// Exists only in the implementation
public DbSet<AccountContact> DbAccountContacts { get; set; }

通过这种设置,我能够使模拟正常工作,并可以对代码进行单元测试。

对于OP来说,这肯定为时已晚,但也许这会帮助那些正在努力解决同一问题的人,就像我一样。

答案 1 :(得分:-2)

我建议您最好保留DbSets并执行集成测试 ,包括 数据库。

因为虽然通过使用数据库模拟进行单元测试可能会有所帮助,但您最好不要使用真实数据库进行测试(但它不是单元测试)。

在ClassInitialize上擦除数据库和/或创建初始数据以进行测试。

如果使用连接字符串创建App.config文件,则可以拥有单独的测试数据库,如果使用的是EF Code First,则可以免费获得。

最好的问候。