2013-02-21 25 views
10

Tôi đã có một dự án ASP.NET WebAPI. Tôi vừa mới tạo các thực thể EntityFramework cho tất cả các bảng dữ liệu của mình. Nhưng tôi không muốn hiển thị lược đồ lớp dữ liệu & cho người dùng của mình. Làm thế nào tôi có thể ánh xạ các thực thể của mình tới một ViewModel (Automapper?) cung cấp kiểu trả về IQueryable để API của tôi hỗ trợ OData?Sử dụng EF và WebAPI, làm cách nào tôi có thể trả về ViewModel AND support IQueryable/OData?

OData hỗ trợ thành phần truy vấn và tham số giống SQL. Tôi đoán tôi cần cung cấp một số loại bản dịch 2 chiều cho phần thành phần truy vấn? Điều đó có nghĩa là một nhà cung cấp LINQ tùy chỉnh? Tôi hy vọng nó dễ hơn thế.

Hoặc tôi có nên từ bỏ IQueryable/OData không?

Trả lời

9

Tôi tìm thấy câu trả lời ở đây: Web API Queryable - how to apply AutoMapper?

Thay vì sử dụng [Queryable] bạn có thể sử dụng một tham số có kiểu ODataQueryOptions<T> để áp dụng hoạt động OData chống lại bất kỳ loại hay LINQ truy vấn mà bạn muốn. Dưới đây là một ví dụ tuyệt vời mà thậm chí không cần phải sử dụng AutoMapper:

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); 
} 

Dưới đây là the Microsoft page giải thích các chi tiết cụ thể của việc sử dụng này. (khoảng một nửa chiều xuống)

+0

là điều này vẫn còn khả thi trong Web Api 2? –

+0

Tuyệt đối! tất nhiên là thế rồi. Bây giờ chỉ có nhiều lựa chọn hơn. –

+3

Tôi không nghĩ phương pháp này hoạt động nữa. Phương thức này không được gọi trừ khi tham số được thay đổi thành ODataQueryOptions . Nếu bạn thay đổi tham số đó, thì phương thức này sẽ được gọi, nhưng odataQuery.ApplyTo() ném một ngoại lệ, nói rằng truy vấn đó áp dụng cho kiểu PersonDto, không phải là Person. – sheamus

1

nếu bạn đang sử dụng Automapper, bạn có thể sử dụng các phép chiếu trong đó. Ví dụ:

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

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

Nó thực sự không phụ thuộc vào việc sử dụng AutoMapper. Đó là một chức năng của thực tế là nhà cung cấp EntityFramework LINQ (ít nhất là với DbContext, ai đó đã nói ObjectContext không hoạt động) hỗ trợ thực tế rằng bạn có thể truy vấn kết quả trên một phép chiếu (Chọn) và nó sẽ nhận ra và dịch nó thành truy vấn trên nguồn dữ liệu gốc. – Rich

+0

LINQ cho phép truy vấn đối với mô hình chế độ xem được dịch sang truy vấn trên nguồn dữ liệu gốc như thế nào? Tôi không hiểu điều đó. Tôi cho rằng nó chắc chắn sẽ không hoạt động nếu chúng ta phải sử dụng một typeconverter (phương pháp tùy chỉnh) để ánh xạ các lớp học? –

+0

Tôi hiểu rằng IQueryable sẽ cho phép các truy vấn OData thực hiện đối với lớp đã dịch, nhưng tôi không thấy cách này có thể hoạt động mà không lấy tất cả 'Sản phẩm' có thể và chuyển đổi chúng thành các thể hiện' ProductDto' trước khi lọc. Làm thế nào để truy vấn OData được dịch sang SQL thích hợp? –

5

Tôi đã kiểm tra thành công điều này bằng lớp ViewModel.

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

trong Get, chọn từ tổ chức của bạn vào viewmodel của bạn:

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

Hãy chắc chắn rằng bạn sử dụng viewmodel phù modelbuilder của bạn trong webapiconfig.cs

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

với điều này, bạn có thể sử dụng url như

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

Tôi xác nhận thông qua profl sql rằng bộ lọc đã được chuyển qua SQL.

Các vấn đề liên quan