Я пытаюсь использовать System.Reflections
для динамического получения DbSet<T>
от его имени.
Сейчас у меня есть:
-
DbSet
name DbSet
Type
, хранящиеся в переменной
Проблема, с которой я сталкиваюсь, возникает при попытке использовать метод dbcontext.Set<T>()
, поскольку (пока это мои попытки):
- Когда я пытаюсь присвоить
<T>
мой DbSet
Type
, он выдает следующую ошибку компиляции: "XXXявляется переменной, но используется как тип "
- Если я попробую использовать оба метода
Extension
, которые вы найдете ниже в моем коде (который я сделал для того, чтобы попытатьсяполучить IQueryable<T>
), он возвращает IQueryable<object>
, что, к сожалению, не то, что я ищу, поскольку, конечно, когда я пытаюсь манипулировать им с помощью дальнейших отражений, ему не хватает всех свойств, которыми обладает исходный класс…
Что я делаю не так?Как я могу получить DbSet<T>
?
Мой код следующий, но, конечно, дайте мне знать, если вам нужно больше информации, пояснений или фрагментов кода.
Мой контроллерМетод :
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);
//...
}
Класс ContextSetExtension
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);
}
}
EDIT Добавлен внутренний код TypeFinder ,
Короче говоря, этот метод делает то же самое с Type.GetType
, но ищет тип на ВСЕХ сгенерированных сборках
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;
}
}
ОБНОВЛЕНИЕ , как запрошено в комментариях, вот конкретный случай:
В моей БД у меня есть несколько таблиц, которые действительно похожи друг на друга, поэтому идея состояла в том, чтобы создать метод динамического обновления таблиц, который был бы хорош для каждой таблицы, просто передавая этому методу таблицуимя, идентификатор строки для обновления и JSON, содержащий данные для обновления.
Итак, вкратце, я бы выполнил некоторые обновления таблицы, заданной на входе как тип DbSet, обновив строку с ID==id
на входе данными, содержащимися в JSON, которые будут проанализированы внутри объекта типа X(то же самое из dbset) / в словарь.
В псевдокоде:
public bool MyMethod (string t, int id, string jsonupdate)
{
string _tableName = t;
Type _type = TypeFinder.FindType(_tableName); //returns the correct type
//THIS DOESN'T WORKS, of course, since as said above:
//<<throws error: "_type is a variable but is used like a type">>
var tableSet = _context.Set<_type>();
//parsing the JSON
var newObj = Newtonsoft.Json.JsonConvert.DeserializeObject(jsonupdate, _type);
//THIS OF COURSE DOESN'T WORKS TOO
//selecting the row to update:
var toUpdate = tableSet.Where(x => x.Id == id).FirstOrDefault();
if(toUpdate!=null)
{
var newProperties = newObj.GetType().GetProperties();
var toUpdateProperties = toUpdate.GetType().GetProperties();
foreach(var item in properties)
{
var temp = toUpdateProperties.Where(p => p.Name==item.Name)
{
//I write it really in briefand fast, without lots of checks.
//I think this is enough, I hope
temp.SetValue(toUpdate, item.GetValue());
}
}
_context.SaveChanges();
}
return false;
}