Предисловие
В моем первом посте на Хабре завязался такой диалог:
A. важно, что к базе нельзя обращаться прямо, только через хранимые-процедуры, а за вызов хранимой процедуры ответственен определенный класс
B. «только через хранимые-процедуры» — что же вы NoSQL-продуктам скажете?
Дальше акцент сместился SQL vs. NoSQL. Но были потеряны основы: работу с базой нужно организовать через специально заточенный класс, а не разбрасывать код вызовов по всему проекту.
Я по прежнему считаю, что NoSQL — это слишком молодые продукты, чтобы они могли конкурировать с реляционными базами на полном серьезе. Но у NoSQL и несколько другая ниша. Мне понадобилось некоторое сохранение данных в проекте, где нет больших объемов. И поэтому я решил попробовать MongoDB. (я бы лучше поработал бы с Oracle NoSQL Database, но не нашел как с этим работать на C#).
Ну в общем все достаточно хорошо, чтобы сохранить объект в базе, оказалось надо сделать совсем мало:
var collection = db.GetCollection();
collection.Save(argObject);
где StrategiesData — тип моего объекта, argObject — собственно мой объект. Но такой стиль поощряет раскидывать как раз обращение к базе по всему проекту. Мешает явное указание типа вида . Ну, что остается отображение. Об этом и поговорим.
Отображение обобщенных методов оказалось сделать не так просто. Вот я и решил поделится, может кому пригодится.
public class Database
{
/// Текущая база данных
IMongoDatabase db;
public void Save(object argObject)
{
MethodInfo MethodGetCollectionGeneric=null;
Type myType = typeof(IMongoDatabase);
MethodInfo[] myMethod = myType.GetMethods();
foreach (MethodInfo m in myMethod)
{
// Выбираем только методы с названием GetCollection
if (m.Name == "GetCollection")
{
ParameterInfo[] pi = m.GetParameters();
// Интересует только такие перегрузки, где возвращаемый тип перегружен,
// а метод не имеет параметров
if (m.ReturnType.IsGenericType && pi.Length==0)
{
MethodGetCollectionGeneric = m;
break;
}
}
}
// Получаем тип нашего объекта
Type ObjectType = argObject.GetType();
Type[] typeArgs = { ObjectType };
// Инстанцируем наш обобщенный метод
MethodInfo MethodGetCollectionGenericMake = MethodGetCollectionGeneric.MakeGenericMethod(typeArgs);
// Выполняем метод
var collection = MethodGetCollectionGenericMake.Invoke(db, null);
collection.Save(argObject);
}
Итого мы имеем более простое обращение к методу сохранения. И всюду работаем с нашим объектом класса Database. А когда понадобится работать с другими базами, в том числе с реляционными, это легко изменится путем настройки класса Database, а вызов останется тем же. В противном же случае, пришлось бы менять код по всему проекту, что в серьезном проекте аналогично самоубийству. Поэтому никогда не разбрасывайте код обращения к конкретной базе данный по проекту — для этого должен быть выделен специальных класс (или их иерархия, и тогда «менеджер задач» — ваш самый главный класс сверху решает куда сохраняться, выбирая того или иного наследника от вашего Database)
Автор: tac