2011-08-21 108 views
6

我迷迷糊糊到下一个问题......我有数据库方面:使用IQueryable的<TEntity>代替DbSet <TEntity>问题

// 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。在这种情况下我该如何使用单元测试?我希望有人已经解决了这个问题呢... 非常感谢提前!

+0

你是否在你的'PrimaryDbContext'中的任何地方声明了一个常量? –

+0

不,只有我以前展示过......并且重写OnModelCreating方法更多... – xtmq

+0

我可以重现这一点。我还看到(使用SQL Profiler)在'IDbContext'情况下,表达式内的'db.ProviderHardwares'被执行为查询,从数据库加载* all *'ProviderHardware'行(* if as *'IDbContext.ProviderHardwares '是IEnumerable'而不是'IQueryable')。然后'Count'和外部查询无法执行,因为内存列表中的对象(“常量”对象列表)不能在SQL中使用。这导致异常。为什么EF将'IDbContext.ProviderHardwares'视为'IEnumerable'而不是'PrimaryDbContext.ProviderHardwares'?没有线索... – Slauma

回答

-2

我建议你最好不要让DbSets做集成测试包括数据库。

因为,尽管通过一个模拟数据库的单元测试可能有点用处,但是用真正的数据库测试会更好(但它不是单元测试)。

在ClassInitialize上擦除数据库和/或创建用于测试的初始数据。

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

此致敬礼。

+0

是的,我认为你是对的.. 但我如何创建和填充代码中的数据库?我可以在PrimaryDbContext中创建域对象。我可以通过EF代码第一个工具自动创建数据库是否在本地sql服务器上包含此对象?并在我的测试中使用它? – xtmq

+0

是的,使用EF Code First,可以在第一次运行应用程序时创建和填充数据库,请查看本教程:(http://www.asp.net/entity-framework/tutorials/creating-an-entity-framework -data-模型换一个-ASP净MVC-应用程序)。另外一个好处是,如果您在测试项目中创建了一个App.config文件,您将获得一个免费的测试数据库,与您的开发数据库无关。我建议你使用SQL Server Compact 4.0。 –

+0

谢谢,我正在阅读本手册=) – xtmq

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来说绝对为时已晚,但也许这可以帮助那些正在为同样问题而奋斗的人,就像我一样。