如何将ASP.NET Web API ODATA合并到ActiveRecord/NHibernate中

如何将ASP.NET Web API ODATA合并到ActiveRecord/NHibernate中,nhibernate,castle-activerecord,asp.net-mvc-4,asp.net-web-api,Nhibernate,Castle Activerecord,Asp.net Mvc 4,Asp.net Web Api,在ASP.NET Web API中,它允许您在url字符串中编写ODATA查询,以指定要从方法返回的数据。然而,我很难理解的是,ODATA的作用是过滤C对象的IQueryable集合,而不是数据库表本身 这是不切实际的,因为您确实希望在数据库级别进行筛选,因为从数据库返回所有对象,将它们加载到一个可查询列表中,然后让ODATA筛选该列表会很糟糕 以下是使用NHibernate和Castle Active Record进行数据访问的代码: public IQueryable<Message&

在ASP.NET Web API中,它允许您在url字符串中编写ODATA查询,以指定要从方法返回的数据。然而,我很难理解的是,ODATA的作用是过滤C对象的IQueryable集合,而不是数据库表本身

这是不切实际的,因为您确实希望在数据库级别进行筛选,因为从数据库返回所有对象,将它们加载到一个可查询列表中,然后让ODATA筛选该列表会很糟糕

以下是使用NHibernate和Castle Active Record进行数据访问的代码:

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的整个概念在现实世界中是完全不切实际的。

以下是我如何让它工作的。非常感谢安德烈亚斯带我去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;
            }

希望这能帮助其他人。现在,我可以针对我的asp.net web api方法编写odata查询,并让它们在db级别进行过滤,这比过滤iqueryable c对象有用得多

以下是我如何让它工作的。非常感谢安德烈亚斯带我去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;
            }

希望这能帮助其他人。现在,我可以针对我的asp.net web api方法编写odata查询,并让它们在db级别进行过滤,这比过滤iqueryable c对象有用得多

请记住,您正在处理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链接附加条件,然后枚举返回结果。

请记住,您处理的是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链接附加条件,然后枚举返回的结果。

添加到@Justin answer,如果没有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;
}

这应该让你接受测试

添加到@Justin answer中,如果没有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;
}

这应该让你接受测试

也许这是一个选项:@Andreas-谢谢你的建议,但是我不知道如何将NHibernate.OData集成到Castle ActiveRecord中:也许这是一个选项:@Andreas-谢谢你的建议,但是我不知道如何将NHibernate.OData集成到Castle ActiveRecord中:我知道在处理iqueryable时它何时会访问数据库,但是在本例中,使用asp.net web api、odata和active record,您建议它首先调用数据库并返回表中的所有记录,然后odata对c列表执行操作并将其过滤。我想,知道如何在nhibernate/activerecord中执行odata命令还不够聪明,因此才有了nhibernate.odata项目。感谢您的建议。我知道在处理iqueryable时,它会在数据库中出现,但是在本例中,使用asp.net web api、odata和active record时,您建议它首先调用数据库并返回表中的所有记录,然后odata对c列表执行操作并对其进行筛选。我想,知道如何在nhibernate/activerecord中执行odata命令还不够聪明,因此才有了nhibernate.odata项目。谢谢你的建议。嗨,贾斯汀,我有点困惑。你能帮我吗?在我的例子中,我将ODataController与webapi一起使用,并将此问题发布在上。非常感谢。嗨,贾斯汀,我有点困惑。你能帮我吗?在我的例子中,我将ODataController与webapi一起使用,并将此问题发布在上。非常感谢。