2009-09-17 3 views
11

Mam zwykły stary obiekt CLR, który jest w zasadzie otoką dla dwóch obiektów struktury encji, robię to, więc mogę przekazać ten obiekt opakowania do mocno wpisanego widoku w strukturze MVC . Moja klasa foo wrapper jest bardzo prosta:Inicjowanie mocno wpisanych obiektów w LINQ do encji

public class FooWrapper 
{ 
    public FooWrapper(Foo f, Bar b) 
    { 
     this.FooObject = f; 
     this.BarObject = b; 
    } 

    public Foo FooObject { get; private set; } 
    public Bar BarObject { get; private set; } 
} 

Co mam tak daleko do mojej funkcji ListFoosWithBars jest następujący:

public IEnumerable<FooWrapper> ListFoosWithBars(int userID) 
{ 
    IEnumerable<Bar> tempBar = ListBarsByUserID(userID); 
    IEnumerable<FooWrapper> results = (from f in _entities.FooSet 
             join b in tempBar on f.ID equals b.foos.ID 
             select new FooWrapper(f, b)); 
    return results; 
} 

To nie działa, ponieważ ewidentnie LINQ do podmioty nie obsługuje sparametryzowanego inicjalizacja, generowany jest wyjątek, który mówi tylko, że: "Tylko konstruktory i inicjatory bez parametrów są obsługiwane w LINQ do encji." Zastanawiałem się, czy istnieje inny sposób osiągnięcia tego samego wyniku?

Odpowiedz

20

jeśli dodać konstruktora bez parametrów do FooWrapper a następnie użyć inicjalizacji obiektu zamiast, tak jak poniżej:

public IEnumerable<FooWrapper> ListFoosWithBars(int userID) 
{ 
    IEnumerable<Bar> tempBar = ListBarsByUserID(userID); 

    IEnumerable<FooWrapper> results = (
     from f in _entities.FooSet 
     join b in tempBar on f.ID equals b.foos.ID 
     select new FooWrapper() 
     { 
      FooObject = f, 
      BarObject = b 
     }); 

    return results; 
} 
+3

Gdyby to samo zostało napisane, wygrywasz. – AdamSane

+0

Doskonale, dziękuję! –

3

Starają się różnych inicjalizacji:

public class FooWrapper 
{ 
    public FooWrapper() { } 

    public Foo FooObject { get; set; } 
    public Bar BarObject { get; set; } 
} 


public IEnumerable<FooWrapper> ListFoosWithBars(int userID) 
{ 
    IEnumerable<Bar> tempBar = ListBarsByUserID(userID); 

    IEnumerable<FooWrapper> results = (
     from f in _entities.FooSet 
     join b in tempBar on f.ID equals b.foos.ID 
     select new FooWrapper 
     { 
      FooObject = f, 
      BarObject = b 
     }); 

    return results; 
} 
+1

+1 dla pominięcia() po nazwie typu w inicjalizatorze. :) –

12

Ok, ale co jeśli chcesz FooObject a BarObject jest tylko do odczytu? Wydaje mi się, że są one nieco wstecz, ponieważ negują możliwość użycia konstruktora na obiekcie.

Widzę wielu ludzi łamiących dobre praktyki enkapsulacji w celu wykorzystania inicjalizacji obiektów w tym scenariuszu.

6

Dlaczego nie używasz .AsEnumerable()? W ten sposób nie będziesz musiał tworzyć konstruktora bez parametrów i to właśnie chcesz.

Twój kod był prawie dobry. Zmień to na:

public IEnumerable<FooWrapper> ListFoosWithBars(int userID) 
{ 
    IEnumerable<Bar> tempBar = ListBarsByUserID(userID); 
    IEnumerable<FooWrapper> results = (from f in _entities.FooSet.AsEnumerable() 
             join b in tempBar on f.ID equals b.foos.ID 
             select new FooWrapper(f, b)); 
    return results; 
} 

Miałem ten sam problem dzisiaj. Miałem klasę z jednym konstruktorem parametrów. Ten konstruktor wypełnił prywatne pole tylko do odczytu, które zostało zwrócone przez właściwość tylko za pomocą polecenia get, a nie zestawu.

+0

To zdecydowanie najlepsze rozwiązanie tego problemu! –

+8

Po prostu byłbym bardzo ostrożny z tym podejściem, ale zasadniczo negujesz korzyści z frameworka Entity, wywołując AsEnumerable. Po określeniu, że skutecznie przenosisz wszystkie rekordy z tabeli FooSet, a następnie wykonujesz połączenie lokalne w pamięci. Wystarczy pomyśleć o skutkach wydajności, gdy masz tysiące (lub miliony) rekordów. – Alan

+0

@Santo Uzgodnione, to podejście powoduje grinds my machine do zatrzymania z instrukcją LINQ na 16 tabel, trwa około pięciu minut, aby zwrócić wynik. Gdyby był niemal natychmiastowy z porównywalną instrukcją SQL. – wonea