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 : EntityObject上T是内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)
所以这T是DbSet<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)
问题
我想你的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。