2014-02-08 47 views
0

ContentType - > EF模型是否可以使用DTO的ODataQueryOptions?

ContentTypes - > DTO

在我的OData控制器:

public Task<IQueryable<ContentTypes>> Get(ODataQueryOptions<ContentTypes> options) 
    { 
     var result = options.ApplyTo(_repository.Query().Get() 
      .Where(u => u.UserId == userId) 
      .OrderBy(o => o.Description)) 
      .Cast<ContentTypes>(); 

     return result; 
    } 

試圖以應用ODataQueryOptions當我得到一個錯誤500。由於該課程已經繼承了ODataController,我甚至需要做options.ApplyTo(...)嗎?

回答

0

解決方法是確保返回類型是DTO的類型,並且將ODataQueryOptions應用於EF實體。然後我使用Automapper將結果映射到DTO。

我已經更新了基於@Schandlich的建議答案,但有些問題依然存在:

[Queryable] 
    public virtual IHttpActionResult Get(ODataQueryOptions<ContentType> options) 
    { 
     var userId = 102; // mock 

     try 
     { 
      var results = options.ApplyTo(_uow.Repository<ContentType>() 
       .Query() 
       .Get() 
       .Include(u => u.User) 
       .Where(u => u.UserId == userId) 
       .OrderBy(o => o.Description)).Cast<ContentType>() 
       .Select(x => new ContentTypeDTO() 
       { 
        //projection goes here 
        ContentTypeId = x.ContentTypeId, 
        Description = x.Description, 
        UserDTO = new UserDTO 
        { 
         UserId = x.UserId, 
         UserName = x.User.UserName 
        } 
       }); 

      return this.Ok(results); 
     } 
     catch (Exception ex) 
     { 
      throw ex; 
     } 
    } 

之所以使用ODataQueryOptions是我想EF處理過濾下來的數據庫調用水平。否則,我會得到所有記錄返回,然後Queryable將踢回去,說結果的第一頁。

我刪除了Automapper代碼,但很好奇爲什麼不使用它?

正如@Schandlich指出的,但是,這不適用於$select$expand

+0

EF濾鏡之後的原因是因爲您處理投影的方式。看看我上面發佈的答案。我也會看你的倉庫,並確保那裏沒有ToList()或其他強制執行方法。此外,當您使用$ select或$ expand時,這將會中斷,因爲結果不會是ContentType類型。 – Schandlich

+0

@Schandlich - 你的建議部分起作用,當我排除'options.ApplyTo()'時,我不會獲得所有其餘的OData信息,例如'$ inlinecount = allpages'的值,因此沒有分頁細節。我不想從數據庫返回所有記錄,然後在客戶端進行過濾。如何處理有數千條記錄的情況呢?你正確的做'$ select'或'$ expand'失敗。我將如何得到這個工作。另外,爲什麼不使用Automapper來完成一些工作? – ElHaix

+0

這是一篇關於爲什麼不使用Automapper的好文章。 http://www.devtrends.co.uk/blog/stop-using-automapper-in-your-data-access-code。分頁不起作用的原因是因爲在應用之前的某個時刻,查詢已經到達數據庫。我不知道它是AutoMapper導致問題還是您的存儲庫。我可能是Cast演講。我會努力讓它開箱即用,而不是試圖強制擴展並選擇與您的設置一起工作。 http://beyondtheduck.com/revisting-projecting-and-the-odata-expand-query-option/ – Schandlich

0

根據@ ElHaix的回答更新了。我不能更強烈地推薦使用AutoMapper來從這樣的數據源映射。這也假定應用於存儲庫的查詢在調用數據庫之前被應用。

[Queryable] 
public virtual IHttpResult Get() 
{ 
    var userId = 102; // mock 

    try 
    { 
     var results = _uow.Repository<ContentType>() 
      .Query() 
      .Get() 
      .Where(u => u.UserId == userId) 
      .OrderBy(o => o.Description) 
      .Select(x => new ContentTypeDTO() 
      { 
       //projection goes here 
      }); 

     return this.Ok(results); 
    } 
    catch (Exception ex) 
    { 
     throw ex; 
    } 
} 

此外,我會嘗試做一個$ select對ElHaix的答案。

+1

隨着'[可查詢]'屬性併除去'options.ApplyTo()',我從服務器31行。由於我想在服務器端應用過濾,因此使用'options.ApplyTo()',將執行詢問10條記錄的sql查詢(而不是稍後在客戶端進行過濾)。 – ElHaix

0

我能用AutoMapper Project()擴展實現這一點。 $ select,$ filter等全部應用於數據庫查詢。

[TestMethod] 
 
     public void DataShaping_With_AutoMapper_And_OData_Select_Test() 
 
     { 
 
      OracleMonitor myMonitor = new OracleMonitor(); 
 
      myMonitor.IsActive = true; 
 

 
      var dbcontext = new MyDbContext(); 
 
      
 
      var datasource = dbcontext.Datasouces; 
 

 
      Assert.IsNotNull(datasource); 
 

 
      SetupAutoMapper(); 
 

 
      var odataQuery = Extensions.CreateDummyODataQuery<DataSourceDTO>("$expand=Fields($select=Description)&$select=Name"); 
 

 
      var withShaping = datasource.Project().To<DataSourceDTO>(); 
 

 
      Assert.IsNotNull(withShaping); 
 

 
      var withODataQuery = odataQuery.ApplyTo(withShaping); 
 
      Assert.IsNotNull(withODataQuery); 
 

 
      string strJson = JsonConvert.SerializeObject(withODataQuery); 
 

 
      Assert.IsFalse(String.IsNullOrEmpty(strJson)); 
 
     }

+0

在一個點上,我用Automapper ...不再。我建議你看看爲什麼使用AutoMapper和EntityFramework將DTO映射到實體是非常可怕的:http://rogeralsing.com/2013/12/01/why-mapping-dtos-to-entities-using-automapper-and-entityframework -is-可怕/ – ElHaix