2015-05-22 4 views
5

Ich habe dieses Problem schon seit einiger Zeit, aber heute habe ich den Wendepunkt erreicht und ich bitte um deine Hilfe.Einen anonymen Typ erstellen, der von verschiedenen Bedingungen abhängt und ihn in eine Klasse umwandeln

Angenommen, ich habe diesen Code:

var query = DbContext.Table.Where(x => x.z == true).Select(x => new { x.a, x.b, x.c }); 
foreach(var item in query) 
{ 
    // Do the work 
} 

ich mit diesem anonymen Typ am Ende und alles ist in Ordnung. Jetzt kommt etwas, das macht mich die Bedingung Where-Klausel, also muss ich eine andere Abfrage machen entsprechend dem Zustand und das ist, wo ich wirklich frustriert bin:

if(something) 
{ 
    var query = DbContext.Table.Where(x => x.z == true && x.zz == false).Select(x => new { x.a, x.b, x.c }); 
    foreach(var item in query) 
    { 
     // Do the work 
    } 
} 
else 
{ 
    var query = DbContext.Table.Where(x => x.z == true).Select(x => new { x.a, x.b, x.c }); 
    foreach(var item in query) 
    { 
     // Do the work 
    } 
} 

, weil die Arbeit in der foreach getan werden Zyklus ist genau der gleiche und ich sollte es nicht wiederholen müssen.

Also, statt mit dem anonymen Art der Arbeit habe ich erklärt, eine neue Klasse und versucht, dies:

class MyQuery 
{ 
    public int a { get; set; } 
    public string b { get; set; } 
    public decimal? c { get; set; } 
} 

IQueryable<MyQuery> query = null; 

if(something) 
{ 
    query = (IQueryable<MyQuery>)DbContext.Table.Where(x => x.z == true && x.zz == false).Select(x => new { x.a, x.b, x.c }); 
} 
else 
{ 
    query = (IQueryable<MyQuery>)DbContext.Table.Where(x => x.z == true).Select(x => new { x.a, x.b, x.c }); 
} 

foreach(var item in query) 
{ 
    // Do the work 
} 

Aber jetzt habe ich eine 'System.InvalidCastException' geworfen, weil ich noch einen anonymen Typ bekommen und offenbar kann es‘ Ich werde in meine Klasse geworfen.

Ich möchte die Wiederholung von Code aus Gründen der Wartung vermeiden, aber ich weiß nicht, wie es geht. Ich fühle, dass ich hier etwas Grundlegendes verpasse, aber nicht finde, was deine Hilfe willkommen und geschätzt ist.

Vielen Dank für Ihre Hilfe.

+0

Ihr zweiter Code würde immer noch mit der anonymen Klasse arbeiten (entfernen Sie einfach die Besetzung). Der einzige Zeitpunkt, an dem Sie eine benutzerdefinierte Klasse benötigen, ist, wann Sie die Daten in eine Methode oder aus einer Methode übernehmen möchten. – juharr

Antwort

9

Sie es sind overcomplicating:

IQueryable<MyQuery> query = DbContext.Table; 

if (something) 
{ 
    query = query.Where(x => x.z == true && x.zz == false) 
} 
else 
{ 
    query = query.Where(x => x.z == true); 
} 

var result = query.Select(x => new { x.a, x.b, x.c }); 

foreach (var item in result) 
{ 
    // Do the work 
} 

Die .Where() Methode des "Typen" der Abfrage nicht ändern!

Hinweis auch, dass diese legal ist:

var query = DbContext.Table.Select(x => new { x.a, x.b, x.c }); 

if (something) 
{ 
    query = DbContext.Table.Where(x => x.z == true && x.zz == false).Select(x => new { x.a, x.b, x.c }); 
} 
else 
{ 
    query = DbContext.Table.Where(x => x.z == true).Select(x => new { x.a, x.b, x.c }); 
} 

foreach (var item in query) 
{ 
    // Do the work 
} 

Ich bin mit der Tatsache, dass anonyme Typen mit den gleichen Parametern (gleicher Name der Parameter, die gleiche Art von Parametern, die gleiche Anzahl von Parametern) innerhalb der Die gleiche Assembly wird vom C# -Compiler "vereinheitlicht". Ich verwende diese Zeile var query = DbContext.Table.Select(x => new { x.a, x.b, x.c }); nur, um den Typ an die Variable var zu "geben". Dann überschreibe ich die Abfrage komplett mit anderen Abfragen, weil die verschiedenen .Select(x => new { x.a, x.b, x.c }); Objekte des gleichen (anonymen) Typs "produzieren".

+0

Ja, ich war überkompliziert. Es war das Grundlegende, das ich vermisste. Danke vielmals. – Francisco

2

Sie können die Where Bedingung ändern, um mit einem Fall oder einem anderen Fall übereinzustimmen. Auf diese Weise müssen Sie sich nicht mehr um doppelten Code kümmern oder eine andere Klasse erstellen, die nur für diese Methode verwendet wird.

var query = DbContext.Table.Where(x => something && (x.z == true && x.zz == false) || !something && (x.z == true)).Select(x => new { x.a, x.b, x.c }); 
foreach(var item in query) 
{ 
    // Do the work 
} 

Oder Sie können einen ternären Vergleich hinzufügen, wie @Rawling erwähnt.

var query = DbContext.Table.Where(x => something ? (x.z == true && x.zz == false) : (x.z == true)).Select(x => new { x.a, x.b, x.c }); 
foreach(var item in query) 
{ 
    // Do the work 
} 
+0

@adricar Beachten Sie, dass manchmal der Abfragecompiler/-optimierer des SQL "entgleist" werden könnte, wenn "tote" Teile von "wo" ... – xanatos

+1

Ich fühle 'x => etwas? (x.z == wahr && x.zz == falsch): (x.z == wahr) 'ist hier klarer. – Rawling

+1

@Rawling du bist ein Genie: D, das sieht besser aus – adricadar

Verwandte Themen