从类型获取DbSet
本文关键字:DbSet 获取 类型 | 更新日期: 2023-09-27 18:26:49
我正在尝试为MVC 6应用程序制作一个通用的表查看器/编辑器。
我目前使用
Context.GetEntityTypes();
给我一张桌子的清单。
现在我需要获取特定类型的数据。我目前的实现是:
// On my context
public IQueryable<dynamic> GetDbSetByType(string fullname)
{
Type targetType = Type.GetType(fullname);
var model = GetType()
.GetRuntimeProperties()
.Where(o =>
o.PropertyType.IsGenericType &&
o.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>) &&
o.PropertyType.GenericTypeArguments.Contains(targetType))
.FirstOrDefault();
if (null != model)
{
return (IQueryable<dynamic>)model.GetValue(this);
}
return null;
}
在我的控制器中使用此代码
[HttpGet("{requestedContext}/{requestedTable}/data")]
public IActionResult GetTableData(string requestedContext, string requestedTable)
{
var data = Request.Query;
var context = GetContext(requestedContext);
if (context == null)
{
return new ErrorObjectResult("Invalid context specified");
}
var entity = context.GetEntity(requestedTable);
if (entity == null)
{
return new ErrorObjectResult("Invalid table specified");
}
var set = context.GetDbSetByType(entity.ClrType.AssemblyQualifiedName);
if (set == null)
{
return new ErrorObjectResult("Invalid table specified - DbSet could not be found");
}
var start = Convert.ToInt32(data["start"].ToString());
var count = Convert.ToInt32(data["length"].ToString());
var search = data["search[value]"];
return new ObjectResult(set.Skip(start).Take(count));
}
照原样,这将返回长度为count
并且从位置为start
的数据。但是,我无法对IQueryable<dynamic>
的特定属性执行查询。
问题是:
- 这似乎是一件微不足道的事情,所以我几乎可以肯定我错过了什么——这一定很容易做到
- 如果不是1,那么我如何将
object set
转换回DbSet<T>
,以便执行查询?如果我设置了一个断点并进行检查,我就可以看到我所有的数据
注意:这是EF7
其他信息:
requestedTable
是完全限定类型EG:<mysystem>.Models.Shared.Users
编辑(2016/5/5)
我最终只是用纯SQL完成了这一切——如果有人能做到这一点,请告诉我!
使用泛型方法和DbContext.Set<TEntity>()
会更简单。您可以在运行时创建一个通用方法,如下所示:
public IActionResult GetTableData(string requestedContext, string requestedTable)
{
var context = GetContext(requestedContext);
if (context == null)
{
return new ErrorObjectResult("Invalid context specified");
}
var entity = context.GetEntity(requestedTable);
if (entity == null)
{
return new ErrorObjectResult("Invalid table specified");
}
var boundMethod = s_getTableDataMethodInfo.MakeGenericMethod(entity.ClrType);
return boundMethod.Invoke(this, new object[] { context }) as IActionResult;
}
private static readonly MethodInfo s_getTableDataMethodInfo
= typeof(MyController).GetTypeInfo().GetDeclaredMethod("GetTableDataForEntity");
private IActionResult GetTableDataForEntity<TEntity>(DbContext context)
where TEntity : class
{
var data = Request.Query;
var start = Convert.ToInt32(data["start"].ToString());
var count = Convert.ToInt32(data["length"].ToString());
var search = data["search[value]"];
return new ObjectResult(context.Set<TEntity>().Skip(start).Take(count));
}
我知道这是一个相当古老的问题,随着时间的推移已经发生了很多变化。如今在EF Core 5&6可以非常简单地实现期望的结果。
EF在后台存储一个列表,其中包含映射的所有类型。这可以通过DbContext.DbSet<T>
访问。
这看起来像这样:
private IQueryable<T> GetDbSetByType<T>() where T : class
{
return DbContext.Set<T>().ToList();
}
当然,更多复杂的查询可能随之而来。为了简单起见,我在这里省略了这一点。