2017-07-21 3 views
-1

Ich habe eine Datenschicht, die abstrahiert die zugrunde liegende Implementierung (Entity Framework) durch die Annahme von & Rückgabe von Modellen, die an anderer Stelle definiert sind. Ich möchte in der Lage sein, ein Func<T, bool> Prädikat an eine der Methoden zu übergeben, um zuzulassen, dass zusätzliche Klauseln bei der Abfrage der Datenbank angewendet werden.Convert Func <TSource, bool> Prädikat zu Func <TDest, bool> Prädikat

Da die generischen Modelle nichts über die zugrunde liegende Entity Framework-Implementierung wissen, muss ich mein Func<T, bool>-Prädikat in ein Prädikat konvertieren, das auf den Entity Framework-Kontext angewendet werden kann.

Die generischen Modelle & Entity Framework-Modelle haben genau die gleichen Eigenschaftsnamen & Ich habe bereits eine Klasse, um die Eigenschaftswertzuordnungen zwischen den beiden durchzuführen. Gibt es eine Möglichkeit, den Zieltyp des generischen Modelldelegaten in den des Entity Framework-Modells zu konvertieren?

Ein Beispiel dessen, was ich bin versucht zu tun: dieser Delegat Gegeben: dbFunc = Func<Models.Order, bool> und es auf den Kontext: func = Func<Schema.Data.Order, bool> ich es konvertieren wollen ctx.Orders.Where(dbDel)

ich this Post gefunden, aber ich kann nicht zusammenfügen, wie die Konvertierung durchgeführt wird. Ich habe mir den ganzen Abend den Kopf dagegen gestoßen, also würde jede Hilfe sehr geschätzt!

UPDATE

Die ursprüngliche Frage & Anforderungen scheinen etwas vage gewesen zu sein, ich werde auf meine Implementierung so erarbeiten & meine Anforderungen. Die folgenden Codebeispiele wurden geändert, um Expression<Func<TIn, TOut>> & nicht Func<TIn, TOut> zu verwenden, basierend auf den Vorschlägen von hvd & Alexei.

Ich habe eine Schnittstelle & eine Reihe von Klassen, die meine Datenschicht darstellen. Diese fungieren als Fassade über der Datenquelle und ermöglichen verschiedene Implementierungen für den Zugriff auf die Datenbank. Ich möchte zusätzliche Filterkriterien übergeben können, da ein Prädikat & dies auf die zugrunde liegende Datenquelle anwenden soll. Da die Fassade jedoch von der zugrunde liegenden Implementierung getrennt ist, wird das Prädikat anhand der Fassadenmodellklassen definiert. Darüber hinaus haben die Eigenschaften der Fassadenmodell-Klassen dieselbe Bezeichnung wie meine Implementierung, so dass beispielsweise direkte Eigenschaftszuweisungen durch Reflektion möglich sind.

Meine Fassade Umsetzung:

namespace Schema.Data 
{ 
    public interface IDataStore 
    { 
     public IEnumerable<Order> GetOrders(string custCode, Expression<Func<Order, bool>> exp); 
    } 

    public class Order 
    { 
     public string CustomerCode { get; set; } 
     public string OrderNumber { get; set; } 
    } 
} 

ich die Schnittstelle in einem eigenen Namensraum dann implementieren, Entity Framework mit meiner Datenbank abzufragen:

namespace Data.EF 
{ 
    // Entity Framework model is in this same namespace 

    public class DataStore : Schema.Data.IDataStore 
    { 
     public IEnumerable<Schema.Data.Order> GetOrders(string custCode, Expression<Func<Schema.Data.Order, bool>> exp) 
     { 
      using (var ctx = new MyDatabaseEntities()) { 
       // TODO: Convert "exp" to Expression<Func<Data.EF.Order, bool>> to pass it in below 
       var orders = ctx.Orders.Where(e => e.CustomerCode == custCode).Where(dbExp ?? (n => true)); 

       // handling the retrieved data & returning result goes here 
      } 
     } 
    } 
} 
+1

'Func dbFunc = order => func (MapSchemaToModel (order)); '... oder suchst du eine bessere Konvertierung? –

+0

Für EF, um etwas nützliches zu erhalten, benötigen Sie einen 'Ausdruck >', kein 'Func '. Welches ist das, was in dem Post verwendet wird, zu dem Sie verlinken, aber nicht nach dem, was Sie in Ihrer Frage hier fragen? – hvd

+0

Sie möchten einen Typ in einen anderen konvertieren, auf den Sie nicht zugreifen können (oder wollen)? Es kommt mir seltsam vor. – HimBromBeere

Antwort

1

Wenn Sie nur Typ-Funktion nimmt ein konvertieren um zu funktionieren, einen anderen Typ zu nehmen, verwenden Sie normalen Zusammensetzungsansatz -

TDest MapSourceToDest(TSource v) {....} 

    Func<TSource, bool> func = ...; 
    Func<TDest, bool> dbFunc = x => func(MapSourceToDest(x)); 

Mapping kann per Hand, Reflexion, Bibliotheken oder vielen anderen Ansätzen erfolgen - How to map properties of two different objects?.

Beachten Sie, dass, wenn Sie tatsächlich benötigen solche Methode zu übergeben Sie Expression und nicht Func EF müssen - in diesem Fall ist es tatsächlich möglich, die Expression mit Zieltyp neu zu schreiben - How to change a type in an expression tree?

+0

Danke für die Erklärung. Wie Sie & hvd vorgeschlagen haben, werde ich eher Ausdrücke verwenden, da dies gegen Entity Framework ausgeführt werden soll. Es ist spät hier, aber ich werde das erste Mal am Morgen versuchen. Bin dankbar. –

+0

@CarlHancke Während EF Ausdrücke analysieren möchte, funktioniert dies immer noch nicht mit EF, da es nicht weiß, was mit MapSourceToDest zu tun ist. Sie müssten den Ausdruck selbst analysieren und selbst einen anderen konstruieren. Aber das ist nicht trivial. –

+0

@Sahuagin Vielen Dank für den Hinweis, ordnungsgemäß zur Kenntnis genommen. Ich bin genau auf dieses Problem gestoßen, als ich versuchte, meine ursprüngliche Lösung zu implementieren. Wie Alexei schon erwähnte, für EF benötige ich eigentlich Ausdrücke, also habe ich meine Fassade entsprechend angepasst. Bei den Expressions wird die Konvertierung vor der EF-Abfrage durchgeführt. Daher wird der EF-Modellausdruck in die Filesprache übersetzt, sodass MapSourceToDest kein Problem darstellt. –

Verwandte Themen