Linq to WCF OData适用于复杂查询吗?

3

目前我们正在评估是否应该使用WCF数据服务作为应用程序的DAL,并且我正在进行POC以查看WCF数据服务是否适用于我们所有的场景。如果我有以下数据模型

DataModel

并且我想要获取所有由Id为1的人订购且价格超过100美元的产品,我应该如何使用Linq to OData来实现,因为在使用OData时,Linq运算符有很多限制。

dbContext.LineItems.Where(li => li.Order.PersonId == 1 && li.Product.Cost > 
120).Select( li => new { Product = li.Product})

上述代码在Sql server上生成了非常晦涩的T-SQL,理想情况下我希望能够从顶部到底部(从订单到产品,如果使用错误的LINQ查询或直接T-SQL)连接表进行逐步细化,但是使用OData似乎总是从底部到顶部,这让我感到不舒服,在某些情况下,在单个查询中查询多个表时会生成非常糟糕的SQL。

在我们的应用程序中,我们期望出现这样的场景,即必须在一个查询中查询(编写条件)最多4个表并选择单个实体。对于这种复杂的查询,OData是否正确?

感谢阅读这篇长文。


在WCF上执行复杂查询是一个不好的想法,这可能意味着您的领域模型过于细粒度。如果您的模型有问题,那么OData是否可以执行复杂查询就无关紧要了。您应该仅公开满足场景所需的实体,而不是详细的数据库架构。 - Panagiotis Kanavos
@PanagiotisKanavos 我相信我们的数据库非常规范化(我假设这是一个正常的数据库设计),表之间关系复杂,我们肯定会出现以下情况:我们需要从表A获取主键,并通过表A-B-C-D依次获取表D上的数据,而表之间的关系可能是1-1、1-*或者多对多的形式。因此我正在思考在这种情况下是否使用OData(WCF数据服务)是个好选择,因为我们的架构师建议将WCF数据服务作为数据访问层(连接数据库的唯一方式,不能直接使用EF)。 - Sri Harsha Velicheti
3个回答

3
在某些情况下,您可能会发现无法在LinQ中生成Odata查询,这并不是说查询不可能,而是Linq提供程序无法执行。在我们项目开始时,我们很快就发现自己先编写Odata查询,然后尝试将其转换为LinQ;我们很快就放弃了这种方法,直接使用Odata进行查询。本文可能会为您提供其他有用的信息:Disadvantages of OData? 特别是关于使用视图的链接文章。

1
WCF数据服务为您提供了访问DataServiceContext实例的方式。如果您已经生成了引用,那么这将为您进行类型化。然而,可用于您的查询操作符是有限的,我预计您将会遇到各种程度的阻力,试图使用它与仅使用Entity Framework和Linq to Entities相比较。我之所以这样期望,是因为虽然我正在使用一个略微不同的数据模型,但它是一个类似的分层模型,并且我从与您一样的较低位置开始查询。
var query = context.DataSources.
Where(x => x.ReportLayouts[0].ReportLayoutID == 1045 &&  x.InstanceName == "hello").
Select(li => new { InstanceName = li.InstanceName });

ToList()的结果

发生了未处理的类型为'System.NotSupportedException'的异常,位于Microsoft.Data.Services.Client.dll中

附加信息:表达式(([10007].ReportLayouts.get_Item(0).ReportLayoutID == 1045) And ([10007].InstanceName == "hello"))不受支持。

为了获取这些数据,我尝试了以下测试:

var query2 = context.DataSources.Select(x => x.ReportLayouts[0].ReportLayoutID == 1045);
var result2 = query2.ToList();

'System.NotSupportedException' 附加信息: 不支持方法 'Select'。

然后我从我的顶级实体开始,相当于你的“Person”,并运行了以下代码:

var query3 = context.Reports.Where(x =>x.ReportLayoutID == 34 &&  x.DatabaseInstance.ServerName == "hello");
var result3 = query3.ToList();

这很好用。我现在正在努力通过导航属性从这个顶层实体到较低层实体。直接使用DataServiceContext类,我可以更容易地组合DataServiceQuery,它直接转换为ODATA支持的URL格式,使用AddQueryOption:
query = query.AddQueryOption("$expand", expandPropertyName);

这样可以通过生成类似于以下的url来显式地加载导航属性:

ReportService.svc/DataSources?expand=dataobjects

生成的服务引用还提供了访问DataServiceContext.LoadProperty方法的功能。一旦加载,您可以查询它,但这涉及到往返传输。
个人而言,我不会将WCF数据服务用作您的DAL,因为这就是Entity Framework的用途。如果您需要使用服务将EF模型公开给外部客户端,则情况有所不同,但是您的DAL仍应该是Entity Framework。对于执行非常简单的CRUD(没有业务逻辑)的应用程序,WCF数据服务是合适的。我不会信任它作为内部运行的复杂查询的DAL。它支持的Web方法也非常简陋,只接受诸如字符串和整数之类的基元参数。如果需要服务,我会调查WCF,但我怀疑在您的情况下不需要服务作为DAL。

关于使用WCF数据服务作为数据访问层的危险,这正是我的想法。当我尝试从4个不同的带有3个条件的表中获取数据时,我要么最终得到太多的数据传输到客户端并在客户端上进行过滤,要么编写一个生成丑陋SQL语句的LINQ表达式。例如,在我的原始数据模型中,如果我在LineItems表中有一个额外的ShippingPriority列,并且我想获取某人订购的所有运输优先级为“2-Day”的行项目,我该如何获取它并在客户端上进行过滤?oDataCOntext.Orders.where( o => o.PersonId==1 && ).Select(o=>new{Li=oi.LineItems}) - Sri Harsha Velicheti
@SriHarshaVelicheti 我假设你的lineItems将是null。要获取默认情况下不返回的lineItems,请参阅此文章http://msdn.microsoft.com/en-us/library/ee358709(v=vs.110).aspx - Jaycee

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接