C#. Реализация Repository без использования ORM

275
08 сентября 2017, 19:24

Я сделал небольшой проект, который собираюсь использовать как ORM при разработке приложений для Windows CE 5.0. Работает он довольно медленно. Помогите пожалуйста оптимизировать работу моей маленькой ORM. Ссылка на github (для .net 3.5)

Больше всего проблем с методами, возвращающими данные из БД. Хотелось бы найти более производительный способ конвертации ответа в объекты.

Нужно вносить изменения, которые будут работать на .net 3.5 compact. Например Expression использовать нельзя.

Update: после замены алгоритма мапинга результатов запроса работать ORM стала быстрее, но она все равно намного медленнее EF, AutoDetectChangesEnabled стоит false

Answer 1

Единственным быстрым вариантом маппинга в .NET 3.5 была генерация делегатов для доступа. Можете взять за основу реализацию PropertyAccessor.Create из Linq To SQL:

Генерация делегата-геттера достаточна тривиальна.

Type dgetType = typeof(DGet<,>).MakeGenericType(objectType, pi.PropertyType);
// pi - ваш PropertyInfo
MethodInfo getMethod = pi.GetGetMethod(true);
Delegate dget = Delegate.CreateDelegate(dgetType, getMethod, true);

Для публичного сеттера (pi.CanWrite) все относительно просто:

dset = Delegate.CreateDelegate(
    typeof(DSet<,>).MakeGenericType(objectType, pi.PropertyType),
    pi.GetSetMethod(true),
    true
    );

С приватным сеттером сложнее, придется делать кодогенериацию через emit:

DynamicMethod mset = new DynamicMethod(
    "xset_" + pi.Name,
    typeof(void),
    new Type[] { objectType.MakeByRefType(), pi.PropertyType },
    true
    );
ILGenerator gen = mset.GetILGenerator();
gen.Emit(OpCodes.Ldarg_0);
if (!objectType.IsValueType) {
    gen.Emit(OpCodes.Ldind_Ref);
}
gen.Emit(OpCodes.Ldarg_1);
gen.Emit(OpCodes.Call, pi.GetSetMethod(true));
gen.Emit(OpCodes.Ret);
drset = mset.CreateDelegate(typeof(DRSet<,>).MakeGenericType(objectType, pi.PropertyType));

DGet и DSet - это ожидаемые сигнатуры для делегатов (аналог современных Action<> и Func<>:

internal delegate V DGet<T, V>(T t);
internal delegate void DSet<T, V>(T t, V v);

Из делегатов выстраивайте цепочки для маппинга всего объекта и кэшируйте по типу, чтобы не генерировать все это при каждом маппинге.

READ ALSO
Как при помощи SqlDependency отслеживать изменения в базе MSSql и отправлять появившиеся данные серверу посредством SignalR

Как при помощи SqlDependency отслеживать изменения в базе MSSql и отправлять появившиеся данные серверу посредством SignalR

Разрабатываю windows-сервисОн должен при помощи SqlDependency отслеживать изменения в базе MSSql (добавление данных) и отправлять появившиеся данные...

249
Почему переменная не является функцией

Почему переменная не является функцией

В первом случае (закомментированом) все нормально работает, но когда пытаюсь присвоить переменной onReady функцию через сеттер, то в setTimeout пишет...

389
return не возвращает нужное значение

return не возвращает нужное значение

Функция считает сколько раз нужно умножить цифры числа друг на друга чтобы получить одну цифруВсё работает, но возвращаемая переменная в console

276
Ошибки модуля jsdom при запуске файла на nodejs

Ошибки модуля jsdom при запуске файла на nodejs

Всем привет! Помогите пожалуйста разобратьсяПри запуске js файла в консоли возникают следующие ошибки (jsdom 11

294