2010-09-08 4 views
6

Ich habe eine halb komplizierte Frage in Bezug auf Entity Framework4, Lambda-Ausdrücke und Datentransferobjekte (DTO).EF4, Lambda, Repository-Muster und DTOs

Also habe ich ein kleines EF4-Projekt, und nach etablierten OO-Prinzipien, ich habe ein DTO, um eine Abstraktionsschicht zwischen den Datenkonsumenten (GUI) und dem Datenmodell bereitzustellen.

  • VideoDTO = DTO mit Getter/Setter verwendet, von der GUI
  • VideoEntity = Entity erzeugt durch EF4

Meine Frage dreht sich um die Verwendung des DTO durch die GUI (und nicht der mit GUI verwendet die Entity überhaupt, kombiniert mit der Notwendigkeit, ein Lambda an die Datenschicht zu übergeben. Meine Datenschicht ist ein Grundlagemuster mit Hinzufügen. Ändern, zu Löschen, Get, GetList etc. Der Versuch, eine Methode Suchen mit einer Unterschrift zu implementieren, wie so:

public IEnumerable<VideoDTO> Find(Expression<Func<VideoEntity, bool>> exp) 
... 
_dataModel.Videos.Where(exp).ToList<Video>() 
--- 

Mein Problem/Anliegen ist die „exp“, um vom Typ VideoEntity sein statt VideoDTO. Ich möchte die Trennung von Bedenken beibehalten, damit die GUI über die Entity-Objekte nicht informiert wird. Aber wenn ich versuche, in

zu übergeben, kann ich nicht dann eine LINQ wo auf diesem Ausdruck mit dem tatsächlichen Datenmodell.

Gibt es eine Möglichkeit, ein Func<VideoDTO,bool> zu einem Func<VideoEntity, bool>

Idealerweise würde meine Methode zu konvertieren Unterschrift Func<VideoDTO, bool> akzeptieren und auf diese Weise die GUI würde keinen Hinweis auf die zugrunde liegende Dateneinheit hat.

Ist das klar genug? Danke für Ihre Hilfe


Danke für die Replies von euch beiden.

Ich werde versuchen, die Suchkriterien in einem Objekt zu definieren und diese im LINQ-Ausdruck zu verwenden. Beginnen Sie mit EF4 und L2S und nutzen Sie dies als Lernprojekt.

Danke nochmal!

Antwort

0

Das Entwurfsziel besteht möglicherweise darin, die Weitergabe von Datenmodellelementen an die Clientebene zu verhindern, anstatt eine Abhängigkeit zwischen der Darstellungsschicht und dem Datenmodell zu verhindern. Auf diese Weise gesehen wäre nichts falsch daran, dass die Abfrage so angelegt wird, wie Sie es angeben.

Um weiter zu gehen, könnten Sie die durchsuchbaren Felder von VideoEntity über eine Schnittstelle (IVideoEntityQueryFields) verfügbar machen und diese als Typ im Ausdruck verwenden.

Wenn Sie Ihren Entitäten keine Schnittstelle hinzufügen möchten, ist die kompliziertere Option die Verwendung eines VideoEntityQuery Objekts und eines Objekts, das eine Expression<Func<VideoEntityQuery,bool>> in eine Expression<Func<VideoEntity,bool>> übersetzt.

1

In Architekturen wie CQRS gibt es keine Notwendigkeit für eine solche Umwandlung überhaupt lesen & schreiben Seiten der App sind getrennt.

Aber in Ihrem Fall können Sie nicht weg von der Übersetzung laufen.

Vor allem - Sie sollten genauer bei der Definition von Repositories sein. Repository-Signatur ist eine Sache, die Sie explizit anstelle von generischen halten möchten.

Gemeinsames Beispiel, um diese Idee zu zeigen - können Sie sagen, welche Indizes Sie in Ihrer Datenbank benötigen, wenn Sie Ihre Repository-Signatur betrachten (vielleicht mit Repository-Implementierung, aber ohne Client-Code)? Du kannst nicht. Weil es zu generisch ist und die Client-Seite nach irgendetwas suchen kann.

In Ihrem Beispiel ist es ein bisschen besser, weil Ausdruck genericness mit dto statt Entity verbunden ist.

Dies ist, was ich tun (mit NHibernate.Linq, aber die Idee bleibt)

public class Application{ 
    public Project Project {get;set;}  
} 

public class ApplicationRepository{ 
public IEnumerable<Application> Search(SearchCriteria inp){ 
     var c=Session.Linq<Application>(); 
     var q=c.AsQueryable(); 
     if(!string.IsNullOrEmpty(inp.Acronym)) 
     q=q.Where(a=>a.Project.Acronym.Contains(inp.Acronym)); 
     /*~20 lines of similar code snipped*/ 
     return q.AsQueryable(); 
} 
} 

//used by client 
public class SearchCriteria{ 
public string Acronym{get;set;} 
/*some more fields that defines how we can search Applications*/ 
} 

Wenn Sie möchten Ihre Ausdrücke zu halten, wäre eine Möglichkeit, Wörterbuch manuell wie folgt zu definieren:

var d=new Dictionary<Expression<Func<VideoDTO,object>>, 
        Expression<Func<VideoEntity,object>>{ 
    {x=>x.DtoPropNumberOne,x=>x.EntityPropNumberOne} /*, {2}, {3}, etc.*/ 
}; 

Und es später verwenden:

//can You spot it? 
//client does not know explicitly what expressions dictionary contains 
_dataModel.Videos.Where(d[exp]).ToList<Video>(); 
//and I'm not 100% sure checking expression equality would actually work 

Wenn Sie nicht über Mapping-Wörterbuch Y schreiben wollen manuell, Sie benötigen einige fortgeschrittene Techniken. Eine Idee wäre, den Dto-Ausdruck in einen String und dann zurück in den Entity-Ausdruck zu übersetzen. Here sind einige Ideen (Sortierung verwandt), die helfen könnten. Ausdrücke sind ziemlich komplizierte Tiere.

Wie auch immer - wie gesagt, Sie sollten dies vermeiden. Sonst - Sie werden wirklich fragilen Code produzieren.