从DbContext检索DbSet <T>的通用方法

Ser*_*e P 12 c# generics entity-framework

我正在使用Entity Framework和一个大型数据库(由200多个表组成).

尝试创建一个返回DbSet<T>特定表T(即类,可以是TableA)的泛型方法.

使用实体数据模型(自动)创建的实体类如下所示:

public partial class sqlEntities : DbContext
{

    public virtual DbSet<TableA> TableA { get; set; }
    public virtual DbSet<TableB> TableB { get; set; }
    public virtual DbSet<TableC> TableC { get; set; }
    ... // other methods

}
Run Code Online (Sandbox Code Playgroud)

我的主要课程是这样的

public class TableModifier
{
   // Should return first 10 elements from a table of that type T
   public IQueryable<T> GetFromDatabase<T>() where T : EntityObject
   {
       try
       {
           using (sqlEntities ctx = new sqlEntities())
           {
               // Get the DbSet of the type T from the entities model (i.e. DB)
               DbSet<T> dbSet = ctx.Set<T>();
               return dbSet.Take(10);
           }
       }
       catch (Exception ex)
       {
           // Invalid type was provided (i.e. table does not exist in database)
           throw new ArgumentException("Invalid Entity", ex);
       }
   }
   ... // other methods
}
Run Code Online (Sandbox Code Playgroud)

我必须设置一个约束where T : EntityObjectT是内EntityObject边界.如果没有这样的约束,DbSet<T> dbSet则会抱怨(即T必须是引用类型),它可能比类型方面的预期要多(基于此).

当我尝试实际调用具有特定类型的方法时,会出现问题.

 [TestMethod]
 public void Test_GetTest()
 {
     TableModifier t_modifier = new TableModifier();

     // The get method now only accepts types of type EntityObject
     IQueryable<TableA> i_q = t_modifier.GetFromDatabase<TableA>();
 }
Run Code Online (Sandbox Code Playgroud)

它给出了一个错误:

There is no implicit reference conversion from 'TableMod.TableA' to
'System.Data.Entity.Core.Objects.DataClasses.EntityObject'.
Run Code Online (Sandbox Code Playgroud)

如果我知道它存在于该实体模型,我怎么能(强制转换?)该TableA类型EntityObject

虽然这是不正确的语法(和逻辑),但这就是我所追求的:

 t_modifier.GetFromDatabase<(EntityObject)TableA>();
Run Code Online (Sandbox Code Playgroud)

如何定义TableA(以及所有其他200个表)类型EntityObject


潜在的解决方案

原来我的约束太具体的,所有我需要改变来自where T : IEntity

where T : class
Run Code Online (Sandbox Code Playgroud)

所以这TDbSet<T>最初预期的类型

保存必须实现添加到200+表类的麻烦,TableA,TableB,...

然后,当然还有其他问题,如更改返回类型IQueryable<T>List<T>,因为IQueryable否则的范围之外返还DbContext(即sqlEntities)使之无用.

小智 9

为什么不尝试将约束更改为类而不是EntityObject

public IQueryable<T> GetFromDatabase<T>() where T : class
Run Code Online (Sandbox Code Playgroud)


Ana*_*uza 0

问题

我想你的TableA类没有实现EntityObject. 这就是您收到此错误的原因。为了解决这个问题,您可以拥有一个抽象类/接口,它将作为所有上下文实体的基础(即 IContextEntity 将具有唯一的 Id 定义):

public class TableA : IContextEntity
{
   ...
}
Run Code Online (Sandbox Code Playgroud)

然后使用相同的方法,但使用新的界面EntityObject,您可以轻松地模拟/测试它

public IQueryable<T> GetFromDatabase<T>() where T : IContextEntity
{
     ...
}
Run Code Online (Sandbox Code Playgroud)


使用情况(测试)

第二个重要的事情是您想要使用此方法的方式。对于实体框架上下文,分离集成测试单元测试非常重要。在您提供的代码中,您尝试访问数据库,这意味着此测试将是集成:

using (sqlEntities ctx = new sqlEntities()) // This will open a DB connection
Run Code Online (Sandbox Code Playgroud)

连接到数据库或外部源通常是一种不好的做法,除非您知道自己在做什么,而这正是如此。如果您只需要一些假/虚拟数据来对其执行操作 - 使用Stubs