2012-01-28 2 views
5

Я вполне уверен, что знаю, что ответ - нет, но как последняя попытка канавы, я думал, что задал бы здесь вопрос.Можно ли изменить выражение IQueryable вручную

Я использую код EF первым для запроса таблицы обычным способом

_context.Set<Foo>().Where(f => f.Bar == 999); 

создающей следующее выражение (я только что написал это так, это может быть неправильно).

{SELECT 
[Extent1].[Test] AS [Test], 
[Extent1].[Test2] AS [Test2], 
FROM [dbo].[Foo] AS [Extent1] 
WHERE 19 = [Extent1].[Bar]} 

Теперь, можно ли вручную изменить этот запрос, чтобы изменить имя таблицы, скажем, на Foo10? (возможно, нет)

В противном случае кто-нибудь знает, как я могу «опоздать связать» имя таблицы в коде первым?

Возможно, вы задаетесь вопросом: «Почему грязный рубить?» Как обычно, это устаревшая проблема с базой данных, которая имеет некоторые проблемы с дизайном и не может быть изменена.

Заранее спасибо.

Ps. Я знаю, что могу использовать Database.SqlQuery, но скорее не буду.

+0

Почему у вас нет таблицы 'Foo10' в вашей модели? – BrokenGlass

+0

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

+0

@mjmcloug, как это зависит? – Krizz

ответ

0

Это не то, что я бы рекомендовал, но вы можете ToString() запрос поставить инструкцию SQL в переменную, а затем заменить имя таблицы. Затем SQL выполняет SQL?

Вонючий и взломанный, но возможно?

+0

Насколько я знаю, возможно только в том случае, если вы готовы отказаться от использования Entity Framework, что означает, что вы также можете писать SQL вручную. – Bevan

+0

Я думал об этом. Вероятно, что эти данные будут прочитаны только для того, чтобы это было удобно. Подумайте, что это немного изворотливое: D –

+0

@ Bevan - это не общая трата. Это будет означать, что мы можем создать выражение в обычном режиме и изменить его в последнюю минуту, вместо того, чтобы иметь новый запрос sql для каждого предложения where, которое мы хотим. –

1

Предполагая, что у вас есть разумное количество таблиц, я бы добавил их все в модель и создавал общий интерфейс, который будут реализовывать все классы, а затем выбрать подходящую модель и использовать Dynamic Linq для запроса.

Я не уверен, если это работает, не проверял и не работал с «EF-код первого», но это то, что я хотел бы попробовать:

Скажем, ваш стол (ы) Foo имеют поля - Bar, Pub, X и пусть X будет соответствовать той, от которой зависит соответствующая таблица?

Затем я определил бы интерфейс:

interface IFoo 
{ 
    int Bar { get; set; } 
    string Pub { get; set; } 
    int X { get; set; } 
} 

Тогда каждая таблица будет иметь свой класс в модели:

[Table("Foo1")] 
class Foo1 : IFoo 
{ 
    public int Bar { get; set; } 
    public string Pub { get; set; } 
    public int X { get; set; } 
} 

[Table("Foo2")] 
class Foo2 : IFoo 
{ 
    public int Bar { get; set; } 
    public string Pub { get; set; } 
    public int X { get; set; } 
} 

Тогда вы можете фильтровать их, как следующее:

IQueryable GetAdequateFoo(int X) 
{ 
    switch (X) // you could use reflection here to dynamically call the given Set<Foo#>() 
    { 
     case 1: 
     return _context.Set<Foo1>(); 
     case 2: 
     return _context.Set<Foo2>(); 
     default: 
     return null; 
    } 
} 

IFoo GetFooByBarAndX(int bar, int X) 
{ 
    IQueryable context = GetAdequateFoo(X); 
    return context.Where("it.Bar == @0", bar).Cast<IFoo>(); 
} 

Это просто не опробованное предложение и написанное от головы, пожалуйста, не голосуйте, если я ошибаюсь и указываю на какой-либо poten проблемы.

+0

Ха, я не собираюсь голосовать за этот ответ, это на самом деле довольно умная идея применить фабричный метод к EF. Я подумаю, хотя у меня также есть классы сопоставления, так что для этого достаточно много классов. Умная идея! –

2

Почему вы не используете наследование на вашей модели TPT?

Как и у ответа Криса, но вы избегаете использования динамического LINQ.

Используя свой комментарий:

если конкретный параметр имеет значение 1 вид в Foo1, если его 2 смотреть в Foo2 и так далее

Таким образом, вы можете сделать это:

var query = ctx 
    .Foos 
    .OfMyType(value) 
    .Where(f => f.Bar == 999) // f.Bar is on the base/abstract entity. 
    .ToList(); 

Где OfMyType является метод пользовательского расширения на IQueryable<T>:

public static IQueryable<T> OfMyType<T>(this IQueryable<T> source, string value) 
{ 
    switch (value) 
    { 
     case "1": 
     return source.OfType<Foo1>(); 
     case "2": 
     return source.OfType<Foo2>(); 
     // etc, etc 
    } 
} 

Большинство (если не все) свойств будут на абстрактном объекте «Foo», и вы создаете производные сущности для каждой из таблиц, каждая из которых имеет свою собственную таблицу поддержки.

Таким образом, «потребляющий» код (например, те, что делают запросы), не нужно заботиться о разных таблицах/Foo, они просто передают «магическое значение» в ваш репозиторий (надеюсь, вы используете его), тогда вы может тихо переключиться на нужный стол.

Будет ли это работать?

+0

Снова это выглядит хорошо. Я должен буду отдать это и вернуться к вам. Но опять же моя единственная проблема - это создание множества классов, которые я пытаюсь избежать. Должен любить наследие! –

+1

+1 Приятно упростить мой подход, используя рамки. – Krizz

Смежные вопросы