0

在ASP.NET的Web API,它可以讓你寫ODATA查詢的URL字符串指定你想從一個方法返回的數據。然而,我很難掌握的部分是ODATA用於過濾IQueryable集合的C#對象,而不是數據庫表本身。如何結合的ASP.NET Web API ODATA到的ActiveRecord/NHibernate的

這是不切實際的,因爲實際上你會想在數據庫級別進行過濾,因爲從數據庫返回所有對象,將它們加載到C#IQueryable列表中,然後使用ODATA過濾器列表會很糟糕。

下面是代碼,它使用NHibernate和城堡活動記錄進行數據訪問:

public IQueryable<Message> GetAll() 
{ 
    return from m in MessageData.FindAllQueryable() 
      select ConvertToView(m); 
} 

public static IQueryable<Message> FindAllQueryable() 
{ 
    var criteria = DetachedCriteria.For<Message>() 
     .CreateAlias("MessageRecipients", "mr") 
     .AddOrder(new Order("Id", false)); 
    return ActiveRecordMediator<Message>.FindAll(criteria).AsQueryable(); 
} 

這段代碼的最終結果將是其返回從數據庫中的所有郵件。如何讓ODATA在數據庫本身上執行過濾器?否則,對於現實世界的情況來說,這個ODATA的整個概念是完全不切實際的。

+3

也許這是一個選項:https://github.com/pvginkel/NHibernate.OData – Andreas 2012-03-05 20:10:58

+0

@Andreas - 感謝您的建議,但是我無法弄清楚如何將NHibernate.OData集成到Castle ActiveRecord中。 :( – Justin 2012-03-05 21:46:15

回答

1

這裏是我最終得到它的工作。非常感謝Andreas帶領我到NHibernate.OData。

在我的控制器動作我從URL中的OData並把它傳遞到我的數據訪問功能:

public IQueryable<Message> GetAll(int authUserId, int userId, DateTime? startDate, DateTime? endDate) 
     { 
      LogWriter.Write(String.Format("Getting all messages for user {0}", userId)); 

      //get messages and convert to view. 
      return from m in MessageData.FindAll(userId, startDate, endDate, GetOData()) 
        select new Message(m); 
     } 

    protected string GetOData() 
      { 
       var odata = this.Request.RequestUri.Query; 
       odata = odata.Substring(odata.IndexOf("$"), odata.Length - odata.IndexOf("$")); 
       odata = odata.Replace("%20", " "); 
       return odata; 
      } 

裏面的數據訪問方法,我們得到NHibernate會話和呼叫session.ODataQuery:

public static IQueryable<Message> FindAll(int userId, DateTime? startDate, DateTime? endDate, string odata) 
      { 
       ICriteria query = GetSession().ODataQuery<Message>(odata); 
       var detachedCriteria = new ConvertedDetachedCriteria(query) 
        .CreateAlias("MessageRecipients", "mr") 
        .Add(Restrictions.Or(
         Restrictions.Eq("SenderUserId", userId), 
         Restrictions.Eq("mr.Key.RecipientId", userId) 
        )); 
       return FindAllQueryable(detachedCriteria); 
      } 

    public static ISession GetSession() 
      { 
       var factory = ActiveRecordMediator.GetSessionFactoryHolder().GetSessionFactories()[0]; 
       return factory.OpenSession(); 
      } 

public static IQueryable<T> FindAllQueryable(DetachedCriteria criteria) 
     { 
      return ActiveRecordMediator<T>.FindAll(criteria).AsQueryable(); 
     } 

同樣,也需要一個簡單的ConvertedDetachedCriteria類,從的ICriteria轉換成的DetachedCriteria。

public class ConvertedDetachedCriteria : DetachedCriteria 
    { 
     public ConvertedDetachedCriteria(ICriteria criteria) 
      : base((CriteriaImpl)criteria, criteria) 
     { 
      var impl = (CriteriaImpl)criteria; 
      impl.Session = null; 
     } 
    } 

希望這會幫助別人。我現在可以寫對我的asp.net網站API方法的OData查詢,並讓他們在分貝水平,這比過濾IQueryable的C#的對象更加有用的過濾!

+0

嗨@Justin,我有點困惑,你能幫助我嗎?在我的情況下,我用'ODataController'和webapi,在[這個鏈接]上發佈了這個問題(https://github.com/pvginkel/NHibernate .OData/issues/8#issuecomment-30580273)。謝謝! – ridermansb 2013-12-14 16:48:15

2

請記住,你正在處理一個IQueryable,這是不是對象的物理目錄。它是一種具有潛在執行並導致實體列表的查詢。這些查詢也可以鏈接在一起:

var query = customRepository.Where(x => x.CustomerName == "John"); //no results generated 
var query2 = query.Where(x => x.Salary > 100000); // still no results generated 
var results = query2.ToList(); // now results are generated 

您應該只能從NHibernate返回一個Session.Query實例。 OData功能會根據URL鏈接附加條件,然後枚舉結果。

+0

我知道它何時處理一個iQueryable,但在這種情況下(與asp。net web api,odata和活動記錄)使用你建議它首先調用數據庫並返回表中所有記錄的方法,然後odata在c#列表上執行並將其過濾。我不知道如何在nhibernate/active record中執行odata命令,因此nhibernate.odata項目是不夠智能的。謝謝你的建議。 – Justin 2012-03-06 03:57:30

0

添加到@Justin答案,沒有ActiveRecord的一個可以只返回類似

public IQueryable<Message> Get() 
{ 
    ICriteria query = _unitOfWork.CurrentSession.ODataQuery<Message>(GetOData()); 
    return query.Future<Location>().AsQueryable<Location>(); 
} 

// Taken from @Justin's answer 
protected string GetOData() 
{ 
    var odata = this.Request.RequestUri.Query; 
    odata = odata.Substring(odata.IndexOf("$"), odata.Length - odata.IndexOf("$")); 
    odata = odata.Replace("%20", " "); 
    return odata; 
} 

這應該把您的測試!