2012-03-16 22 views
13

to LINQ-SQLprzejściu w Expression do LINQ za Select

mam dużo różnych klasach wszystko robi tego samego zapytania, ale wystające wyniki nieco inaczej. Idealnie chciałbym móc mieć zapytanie w jednym miejscu i przekazać projekcję do metody Select. To działa dobrze dla konkretnych typów:

public void GetResults() { 
    var junk = db.SiteProducts.Select(Project()); 
} 

public Expression<Func<DbEntities.SiteProduct, string>> Project() { 
    return p => p.ProductAlert; 
} 

Ale gdy próbuję wrócić typ anonimowy, to nie

public void GetResults() { 
    var junk = db.SiteProducts.Select(Project()); 
} 

public Expression<Func<DbEntities.SiteProduct, TResult>> Project<TResult>() { 
    return p => new { p.ProductAlert }; 
} 

pełni rozumiem dlaczego rodzajowe typu wnioskowanie zawodzi w drugim przypadku. Ale czy istnieje jakaś sztuczka polegająca na tworzeniu własnych Wyrażeń od podstaw - brakuje mi tego, aby to zadziałało?

+0

Coś takiego? http://stackoverflow.com/questions/1299534 –

+0

@Robert - ten przykład wydaje się próbować napisać zamiennik dla Where, który jest nieco inny. Ale mógłbym czegoś nie zauważyć. Ale dziękuję. –

+0

Istnieje również: http://stackoverflow.com/questions/4683427, który może być nieco bliżej tego, co próbujesz zrobić. –

Odpowiedz

0

Jeśli dobrze rozumiem Twoje pytanie można użyć tego kodu:

najpierw zadeklarować metodę selekcji danych tak:

public List<TResult> FindAll<TResult>(Func<Regions, TResult> selector) where TResult : class 
    { 
     using (RepositoryDataContext = new DataClasses1DataContext()) 
     { 
       return RepositoryDataContext.Regions.Select<Regions, TResult>(selector).ToList<TResult>(); 

     } 
    } 

wtedy można zbudować select tak:

Func<Regions, SelectAllRegion> select = r => new SelectAllRegion 
     { 
      RegionID = r.RegionID, 
      RegionDescription = r.RegionDescription 
     }; 

mój SelectAllRegion:

public class SelectAllRegion 
{ 
    public SelectAllRegion() 
    { 
    } 
    public int RegionID { get; set; } 
    public string RegionDescription { get; set; } 
} 

i region jest Region stół w northwing.I nadzieję, że to pomoże Ci

2

IdeaBlade ma klasę ProjectionSelector, której można użyć do abstrakcji swoich prognoz. Jeśli potrzebujesz skonstruować zapytanie rzutowania, ale nie znasz typów w czasie kompilacji, możesz utworzyć instancję klasy ProjectionSelector i przekazać informacje o typie w czasie wykonywania.

Klasa i kod przykładowy, można znaleźć tutaj:

tworzyć dynamiczne "Wybierz", "SelectMany" i "klauzule" GroupBy
http://drc.ideablade.com/xwiki/bin/view/Documentation/dynamic-projection

+0

Dzięki Robert. Istnienie tego projektu skłania mnie do przekonania, że ​​nie ma cukru syntaktycznego, który można posypać, aby działało tak, jak jest, ale na wszelki wypadek otworzę go nieco bardziej. –

+0

Mogą emitować IL pod maską. W ten sposób sprawiają, że ich anonimowa klasa działa podczas pracy. –

+0

Istnieje również ten fascynujący kawałek kodu: http://msdn.microsoft.com/en-us/vstudio/bb737920#dynsel –

2

To nie będzie działać na compile- czas. Korzystając z dynamicznych rzeczy, możesz sprawić, by działało to oczywiście.

Prostym rozwiązaniem nie jest użycie anonimowego typu, ale niestandardowa klasa DTO. Taka klasa DTO zajmuje tylko kilka linii i jest łatwa w utrzymaniu. Zwykle jest to dobre rozwiązanie.

2

Jest to intrygujące pytanie. Myślę, że DTO może ci pomóc, ale istnieją ograniczenia i pułapki, na które trzeba uważać. Podjąć następujące LINQPad Przykład:

class ProjectDTO 
{ 
    public string Name { get; set; } 

    public static Expression<Func<Project, ProjectDTO>> ToDTO = (e) => new ProjectDTO 
    { 
     Name = e.Name 
    }; 

    public ProjectDTO() {} 

    public ProjectDTO(Project project) 
    { 
     Name = project.Name; 
    } 
} 

void Main() 
{ 
    Projects.Select(p => p.Name).Dump(); 
    Projects.Select(ProjectDTO.ToDTO).Dump(); 
    Projects.Select(p => new ProjectDTO(p)).Dump(); 
} 

SQL generowane:

SELECT [t0].[Name] 
FROM [Project] AS [t0] 
GO 

SELECT [t0].[Name] 
FROM [Project] AS [t0] 
GO 

SELECT [t0].[ProjectId], [t0].[Name], [t0].[Description], [t0].[DateCreated], [t0].[DateModified], [t0].[DateComplete], [t0].[CreatedBy] 
FROM [Project] AS [t0] 

Jak widać, nie można korzystać z kopiowaniem konstruktora przypisać właściwości DTO jak to zmusza cały obiekt do pobrania z bazy danych.

To również nieznacznie ograniczające, jeśli chcesz rozszerzyć podstawowy DTO i dodać więcej właściwości dla bardziej wyspecjalizowanych widoków danych, co oznacza, że ​​możesz otrzymać wiele Wyrażeń z podobnym kodem.

Jednak Lubię Opcja druga, ale jestem pewien, że ta opcja jest całkiem prawdopodobne, ograniczone do pojedynczych prognoz typu Rozważmy następujący przykład:

var query = from p in Projects 
      join t in Tasks on p.ProjectId equals t.ProjectId 
      select ProjectDTO.ToDTO; //Can't be used like this 

I nie sądzę, można użyć wyrażenia w tego typu składni zapytania. Ogólnie rzecz biorąc, nie wydaje mi się, aby istniało rozwiązanie, które będzie działać we wszystkich obszarach. Być może trzeba będzie przejrzeć swój projekt, aby sprawdzić, czy można przewidzieć mniej prognoz, na podstawie niektórych właściwości są bardzo tanie, aby zawsze uwzględnić w zapytaniu?

Bez użycia biblioteki Dynamic LINQ lub ręcznego budowania drzewa ekspresji chciałbym również sprawdzić, czy jest możliwe, aby LINQ-SQL/LINQ-Entities tworzyły dynamiczne selekcje.