Могу ли я создать универсальный CompiledQuery, который принимает несколько таблиц и универсальных типов? - PullRequest
2 голосов
/ 13 января 2009

У меня есть несколько таблиц с компонентом "id". Я хотел бы использовать LINQ для получения элемента из одной из этих таблиц с правильным типом LINQ-To-SQL, но только с использованием одного CompiledQuery.

Вот пример, который работает в настоящее время. Скажем, тип объекта, определенный в DBML, - «myitem», а его таблица - «myitems».

    var getOneItem = CompiledQuery.Compile(
        (MyDataContext db, long id) => ((from i in db.myitems
                                              where i.id == id
                                              select i).SingleOrDefault()));

Я хотел бы сделать это, где типом может быть "myitem", "myitems2" или любой другой тип таблицы и объекта, который меня может заинтересовать.

    var getOneItemAnyTable = CompiledQuery.Compile(
        (Table tab, Type T long id) => ((from anItem in tab<T>
                                              where anItem.id == id
                                              select anItem).SingleOrDefault()));

Я составил этот синтаксис, потому что я не уверен, как этот синтаксис должен выглядеть здесь. Есть идеи, если это возможно? Придется ли мне разбирать DBML, чтобы создать какой-то суперкласс для задействованных типов?

Спасибо.

Ответы [ 2 ]

2 голосов
/ 13 января 2009

Вместо этого выведите все ваши сущности из базовой сущности, которая имеет общие свойства в ваших сущностях (например, Id). Реализация этих слоев с помощью POCO поможет вам.

1 голос
/ 13 января 2009

Я почти уверен, что вы не можете сделать один скомпилированный запрос охватывающим несколько таблиц (если вы это имеете в виду); как бы знать где искать? EF поддерживает что-то вроде этого с наследованием (и несколькими таблицами), но даже с наследованием LINQ-to-SQL поддерживает только одиночную таблицу различаемое наследование.

Суть этого вопроса во многом идентична с этим с более раннего сегодняшнего дня. Сложный бит является первичным ключом, поскольку его трудно определить абстрактно. Остальное просто GetTable<T> (по крайней мере, с LINQ-to-SQL).

В этом случае вам не нужен суперкласс - просто способ получить первичный ключ. К счастью, я напоминаю, что LINQ-to-SQL предлагает способ сделать это (без необходимости использовать атрибуты, что не является обязательным требованием LINQ-to-SQL); следующее не прекомпилируется (и не проверено), но должно быть довольно близко:

( обновление исправлено и протестировано)

Первое использование:

Foo foo = ctx.Get<Foo>(fooid);
Bar bar = ctx.Get<Bar>(barid);

код:

    public static TItem Get<TItem, TKey>(
        this DataContext ctx, TKey key)
        where TItem : class
    {
        var table = ctx.GetTable<TItem>();
        var primaryKey = ctx.Mapping.GetMetaType(typeof(TItem))
                .DataMembers.Where(
            member => member.IsPrimaryKey).Single().Member.Name;

        var item = Expression.Parameter(typeof(TItem), "item");
        var lambda = Expression.Lambda<Func<TItem, bool>>(
            Expression.Equal(
                Expression.PropertyOrField(item, primaryKey),
                Expression.Constant(key, typeof(TKey))),
                item);
        return table.Single(lambda);
    }
    public static TItem Get<TItem>( // common case
        this DataContext ctx, int key)
        where TItem : class
    {
        return Get<TItem, int>(ctx, key);
    }
    public static TItem Get<TItem>( // common case
       this DataContext ctx, string key)
       where TItem : class
    {
        return Get<TItem, string>(ctx, key);
    }

Я посмотрю, смогу ли я найти способ предварительно скомпилировать его ...

...