2012-01-28 7 views
5

Jestem prawie pewny, że wiem, że odpowiedź jest nie, ale jako ostatnia próba dna, myślałem, że zadam to pytanie.Czy można ręcznie zmodyfikować wyrażenie IQueryable?

Używam kod EF pierwszy kwerendy w tabeli w zwykły sposób

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

który tworzy następujące wyrażenie (Właśnie tak napisane to może być źle).

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

Teraz możliwe jest ręczne modyfikowanie tego zapytania, aby zmienić nazwę tabeli do, powiedzmy, Foo10? (prawdopodobnie nie)

W przypadku braku tego, czy ktoś wie, w jaki sposób mogę "późno związać" nazwę tabeli w kodzie?

Pewnie zastanawiasz się: "Po co ten brudny hack?" Jak zwykle jest to starszy problem z bazą danych, która ma problemy z projektowaniem i nie można jej zmienić.

Z góry dziękuję.

Ps. Jestem świadomy, że mogę użyć Database.SqlQuery, ale wolałbym nie.

+0

dlaczego nie masz również tabeli "Foo10" w swoim modelu? – BrokenGlass

+0

Ponieważ technicznie jest to ten sam model rozłożony na wielu tabelach. Tabela, w której znajdują się twoje dane, zależy od parametru –

+0

@mjmcloug, od czego to zależy? – Krizz

Odpowiedz

0

To nie jest coś, co polecam, ale możesz ToString() zapytanie, aby umieścić instrukcję SQL do zmiennej, a następnie ciąg zastąpić nazwę tabeli. Następnie SQL wykonać to SQL?

Śmierdząca i hacky, ale możliwe?

+0

Z tego, co wiem, jest to tylko możliwe, jeśli chcesz zrezygnować z używania Entity Framework - co oznacza, że ​​równie dobrze możesz napisać kod SQL ręcznie. – Bevan

+0

Myślałem o zrobieniu tego. Jest prawdopodobne, że dane te będą tylko do odczytu, więc może być odpowiednie. Myślę jednak, że jest trochę podejrzanie: D –

+0

@Bevan nie jest całkowitym marnotrawstwem. Będzie to oznaczać, że możemy budować wyrażenie w zwykły sposób i zmieniać go w ostatniej chwili, zamiast mieć nowe zapytanie SQL dla każdego zdania, gdzie chcemy –

1

Zakładając, że dysponujesz rozsądną liczbą tabel, dodaję je wszystkie do modelu i utworzę wspólny interfejs, a następnie wszystkie klasy zostaną zaimplementowane, a następnie wybierz odpowiedni model i użyję Dynamic Linq do odpytania.

Nie jestem pewien, czy to działa, nie sprawdziłem go i nie pracował z „EF code-first”, ale to jest coś, co chciałbym spróbować:

Powiedzmy swój Stół (y) Foo mieć pola - Bar, Pub, X i pozwolić X być tym, od którego zależy odpowiednia tabela?

Następnie chciałbym zdefiniować interfejs:

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

Następnie każdy stół będzie miał swoją klasę w modelu

[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; } 
} 

Następnie można filtrować je jak następuje:

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>(); 
} 

To jest po prostu nie sprawdzona sugestia i napisana z głowy, proszę nie głosujcie w dół, jeśli się mylę i wskażcie jakąkolwiek poten problemy.

+0

Ha, nie zamierzam głosować na tę odpowiedź, to całkiem sprytny pomysł, aby zastosować metodę fabryczną do EF. Nie będę się nad tym zastanawiał, ponieważ mam również zajęcia z mapowania, więc jest dużo zajęć, aby to ustawić. Sprytny pomysł! –

2

Dlaczego nie używasz dziedziczenia TPT w swoim modelu?

Podobny do odpowiedzi @ Krizz'a, ale unikasz używania dynamicznego LINQ.

Korzystanie swój komentarz:

czy dany parametr ma wartość 1 wygląd w foo1 jeśli jego 2 wyraz foo2 i tak dalej

So, można to zrobić:

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

Gdzie OfMyType to sposób niestandardowy rozszerzenie na 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 
    } 
} 

Większość (jeśli nie wszystkie) nieruchomości będzie na abstrakcyjnym elemencie "Foo", a użytkownik utworzy elementy pochodne dla każdej z tabel, z których każda ma własną tabelę pomocniczą.

W ten sposób, "konsumujący" kod (np. Te, które robią zapytania), nie muszą przejmować się różnymi tabelami/Foo, po prostu przekazują "magiczną wartość" do twojego repozytorium (mam nadzieję, że korzystasz z niego), a następnie można w trybie cichym przełączyć na żądany stół.

Czy to działa?

+0

Znowu wygląda dobrze. Muszę dać ci szansę i wrócić do ciebie. Ale znowu moim jedynym problemem jest generowanie wielu zajęć, których staram się unikać. Muszę uwielbiać dziedzictwo! –

+1

+1 Miło uprościć moje podejście, korzystając z tego, co oferuje struktura. – Krizz

Powiązane problemy