我正在尝试使用System.Reflections
从其名称动态获取DbSet<T>
。
我现在得到的是:
DbSet
名称DbSet
的{{1}}存储在变量中我尝试使用Type
方法时遇到了我面临的问题,因为(到目前为止,这是我的尝试):
dbcontext.Set<T>()
<T>
分配给DbSet
时,会引发以下编译错误:
“ XXX是变量,但像类型一样使用”
Type
方法(我为了获得Extension
而做出),它将返回IQueryable<T>
,不幸的是,这不是我想要的,因为当我尝试进一步进行反射时,它当然缺少原始类具有的所有属性……我在做什么错?我如何获得IQueryable<object>
?
以下是我的代码,但是,当然,如果需要更多信息,说明或代码段,请告诉我。
我的控制器的方法:
DbSet<T>
类 ContextSetExtension
public bool MyMethod (string t, int id, string jsonupdate)
{
string _tableName = t;
Type _type = TypeFinder.FindType(_tableName); //returns the correct type
//FIRST TRY
//throws error: "_type is a variable but is used like a type"
var tableSet = _context.Set<_type>();
//SECOND TRY
//returns me an IQueryable<object>, I need an IQueryable<MyType>
var tableSet2 = _context.Set(_type);
//THIRD TRY
//always returns me am IQueryable<object>, I need an IQueryable<MyType>
var calcInstance = Activator.CreateInstance(_type);
var _tableSet3 = _context.Set2(calcInstance);
//...
}
编辑,添加了 TypeFinder 的内部代码。
简而言之,此方法的作用与public static class ContextSetExtension
{
public static IQueryable<object> Set(this DbContext _context, Type t)
{
var res= _context.GetType().GetMethod("Set").MakeGenericMethod(t).Invoke(_context, null);
return (IQueryable<object>)res;
}
public static IQueryable<T>Set2<T>(this DbContext _context, T t)
{
var typo = t.GetType();
return (IQueryable<T>)_context.GetType().GetMethod("Set").MakeGenericMethod(typo).Invoke(_context, null);
}
}
相同,但是在所有生成的程序集上搜索Type
Type.GetType
更新,具体请参见注释:
在我的数据库中,我有一些表彼此之间非常相似,因此我们的想法是创建一个动态表更新方法,该方法对每个表都适用,只需将表名,ID传递给该方法要更新的行和包含要更新的数据的JSON。
因此,简而言之,我将对输入中作为DbSet类型给出的表进行一些更新,并使用包含在JSON中的数据对输入中的public class TypeFinder
{
public TypeFinder()
{
}
public static Type FindType(string name)
{
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
var result = (from elem in (from app in assemblies
select (from tip in app.GetTypes()
where tip.Name == name.Trim()
select tip).FirstOrDefault())
where elem != null
select elem).FirstOrDefault();
return result;
}
}
进行更新,以将其解析为一个对象类型X(与dbset相同)/进入字典。
使用伪代码:
ID==id
答案 0 :(得分:1)
public
function validatePlanEntries(Request $request)
{
$validation = $this->validate($request, [
'WithSpouse' => (\Input::has('spouse')) ? 1 : 0;
]
}
嗯,那永远都行不通。您的IQueryable不能为returns me an IQueryable<object>, I need an IQueryable<MyType>
类型,因为这意味着编译器将需要知道IQueryable<MyType>
是什么,而这是不可能的,因为此练习的全部目的是在运行时确定。 >
也许知道这些对象实际上是MyType
的实例?
如果没有,我想您已经把自己粉刷到这里的角落里了,并且您正在尝试找出要用来摆脱该状况的油漆。退后一步,这可能不是技术问题。 为什么,您需要这样做吗?为什么只有在运行时才知道类型而在编译时才知道类型的矛盾需求?
您需要考虑自己的要求,而不是技术细节。
答案 1 :(得分:0)
编辑:已测试并且可以正常运行:
java.lang.RuntimeException: Exception getting JDBC Driver
重要提示:您的DbContext需要声明DbSet正常工作!
public async Task<bool> MyMethod(string _type)
{
Type type = Type.GetType(_type);
var tableSet = _context.Set(type);
var list = await db.ToListAsync();
// do something
}
// pass the full namespace of class
var result = await MyMethod("Namespace.Models.MyClass")
答案 2 :(得分:0)
我需要从数据库中为已知类型列表中的每种类型动态加载单个记录,以便在管理员编辑模板时打印测试电子邮件,所以我这样做了:
List<object> args = new List<object>();
//...
//other stuff happens that isn't relevant to the OP, including adding a couple fixed items to args
//...
foreach (Type type in EmailSender.GetParameterTypes())
{
//skip anything already in the list
if (args.Any(a => a.GetType().IsAssignableFrom(type))) continue;
//dynamically get an item from the database for this type, safely assume that 1st column is the PK
string sql = dbContext.Set(type).Sql.Replace("SELECT", "SELECT TOP 1") + " ORDER BY 1 DESC";
var biff = dbContext.Set(type).SqlQuery(sql).AsNoTracking().ToListAsync().Result.First();
args.Add(biff);
}
警告:我知道我正在执行此操作的所有实体都至少存在一个记录,并且每种类型只能有一个实例可以传递给电子邮件生成器(它有许多 Debug.Asserts 来测试实施)。
如果您知道要查找的记录 ID,而不是整个表,则可以使用 dbContext.Set(type).Find()
。如果您想要任何类型的整个表格,您可以这样做:
string sql = dbContext.Set(type).Sql; //append a WHERE clause here if needed/feasible, use reflection?
var biff = dbContext.Set(type).SqlQuery(sql).ToListAsync().Result;
感觉有点笨重,但它有效。奇怪的是没有没有 Async 的 ToList,但我可以在这里同步运行。在我的情况下,关闭代理创建是必不可少的,但您看起来想要维护上下文状态,以便您可以写回 db。我稍后会做大量的反射,所以我并不真正关心强类型这样的结果集合(因此是 List<object>
)。但是一旦你有了集合(即使只是作为对象),你应该能够像你在 UPDATE 示例代码中所做的那样使用 System.Reflection,因为你知道类型并且可以在这样的情况下使用带有已知/给定属性名称的 SetValue方式。
我正在使用 .NET Framework,但希望这可以转换为 .NET Core。