2013-02-21 5 views
10

Ich habe ein ASP.NET WebAPI-Projekt. Ich habe kürzlich EntityFramework-Entitäten für alle meine Datentabellen erstellt. Aber ich möchte meine Datenschicht & nicht meinen Benutzern zugänglich machen. Wie kann ich meine Entitäten einem ViewModel (automapper?) Zuordnen und bieten IQueryable Rückgabetyp, so dass meine API OData unterstützt?Wie kann ich mithilfe von EF und WebAPI ein ViewModel zurückgeben und IQueryable/OData unterstützen?

OData unterstützt Abfragezusammensetzung und SQL-ähnliche Parameter. Ich denke, ich müsste eine Art 2-Wege-Übersetzung für den Teil der Fragestellung bereitstellen. Bedeutet das einen benutzerdefinierten LINQ-Anbieter? Ich hoffe, es ist einfacher als das.

Oder sollte ich auf IQueryable/OData aufgeben?

Antwort

9

fand ich die Antwort hier: Web API Queryable - how to apply AutoMapper?

Statt [Queryable] verwenden Sie ODataQueryOptions<T> einen Parameter des Typs verwenden können OData Operationen gegen jede Art oder LINQ-Abfrage Sie anwenden möchten. Hier ist ein gutes Beispiel, das nicht einmal braucht AutoMapper zu verwenden:

public virtual IQueryable<PersonDto> Get(ODataQueryOptions<Person> odataQuery){ 
    odataQuery.Validate(new ODataValidationSettings(){ 
     AllowedFunctions = AllowedFunctions.AllMathFunctions 
    }); 
    var people = odataQuery.ApplyTo(uow.Person().GetAll()); 
    return ConvertToDtos(people); 
} 

Hier the Microsoft page erklärt die Besonderheiten dieser Nutzung. (etwa auf halbem Weg)

+0

ist das noch in Web Api 2 möglich? –

+0

Absolut! natürlich ist es das. Jetzt gibt es nur mehr Möglichkeiten. –

+3

Ich glaube nicht, dass diese Methode nicht mehr funktioniert. Die Methode wird erst aufgerufen, wenn der Parameter in ODataQueryOptions geändert wird. Wenn Sie den Parameter auf diesen Wert ändern, wird die Methode zwar aufgerufen, aber odataQuery.ApplyTo() löst eine Ausnahme aus und sagt, dass die Abfrage auf den Typ PersonDto und nicht auf Person angewendet wird. – sheamus

1

Wenn Sie Automapper verwenden, können Sie Projektionen darin verwenden. Beispiel:

public class ProductsController : EntitySetController<Product, int> 
    { 
     private DbProductsContext _db = new DbProductsContext(); 

     public override IQueryable<ProductDto> Get() 
     { 
      return _db.Products.Project().To<ProductDto>(); 
     } 
    ... 
+0

Es ist wirklich unabhängig von der Verwendung von AutoMapper. Es ist eine Funktion der Tatsache, dass der EntityFramework LINQ-Provider (zumindest mit DbContext, jemand sagte, dass ObjectContext nicht funktioniert) die Tatsache unterstützt, dass Sie Ergebnisse auf einer Projektion abfragen können (Select) und es in einer Abfrage erkennen und übersetzen wird die ursprüngliche Datenquelle. – Rich

+0

Wie ermöglicht LINQ, dass Abfragen für das Viewmodel in eine Abfrage für die ursprüngliche Datenquelle übersetzt werden? Ich verstehe das nicht. Ich nehme an, dass es definitiv nicht funktionieren würde, wenn wir einen Typkonverter (benutzerdefinierte Methode) verwenden müssen, um Klassen zuzuordnen? –

+0

Ich verstehe, dass IQueryable erlauben würde, OData-Abfragen gegen die übersetzte Klasse auszuführen, aber ich sehe nicht, wie dies funktionieren könnte, ohne alle möglichen 'Produkte' abzurufen und sie in 'ProductDto'-Instanzen vor dem Filtern zu konvertieren. Wie kann die OData-Abfrage in das richtige SQL übersetzt werden? –

5

Ich konnte dies erfolgreich mit einer ViewModel-Klasse testen.

public class InvoiceViewModel 
{ 
    public int InvoiceID { get; set; } 
    public string InvoiceNumber { get; set; } 
} 

in dem erhält, wählen Sie aus Ihrem Unternehmen in Ihr Viewmodel:

public override IQueryable<InvoiceViewModel> Get() 
    { 
     var ctx = new CreditPointEntities(); 
     return ctx.Invoices.Select(i => new InvoiceViewModel 
      { 
       InvoiceID = i.InvoiceID, 
       InvoiceNumber = i.InvoiceNumber 
      }).AsQueryable(); 
    } 

Stellen Sie sicher, dass das Ansichtsmodell in Ihrer Modellbauer Linie in webapiconfig.cs mit diesem

modelBuilder.EntitySet<InvoiceViewModel>("Invoice"); 

verwenden, Sie können eine URL wie

http://website/odata/Invoice?$filter=InvoiceID eq 1

012 verwenden

Ich bestätigte durch SQL Profiler, dass der Filter an SQL übergeben wurde.

Verwandte Themen