Mik*_*ike 1 wcf-data-services odata breeze
我在尝试过滤数据时遇到问题,因为breeze在URL的末尾添加了$ filter子句,而WCF\odata服务正在抛出过滤器,不能在select子句之后.
public IQueryable<order> Orders()
{
string owner= Membership.GetUser(Thread.CurrentPrincipal.Identity.Name).owner;
IQueryable<Consigne> q = this.db.Consignes
// .AddQueryOption("Dest", dest)
.Where(x => x.Owner == owner)
.Select(f => new order{ Name= f.Name, Address1 = f.Address1, Address2 = f.Address2, Address3 = f.Address3 });
return q;
}
Run Code Online (Sandbox Code Playgroud)
我已经使用服务器端Where子句限制结果集,并使用Select投影限制字段.如果我删除这些并让微风完全控制Where\Select然后我吹我的安全模型允许js代码控制.
我意识到这不是一个真正的微风问题而是更多的odata问题,但其他人如何处理这个?你是放弃iQueryable而只是创建一个webapi并传回json?如果是这样,那么我正在重新发明轮子,因为我还需要处理skip\take和orderby.
感谢建议:)亲切的问候,迈克
解决了
我发现WCF无法在不丢失TotalCount的情况下作为iQueryable传递.WCF返回一个QueryOperationResponse,我可以将其传递给breeze,但是一旦通过微风转换为对象,我就无法在Breeze的QueryHelper.WrapResults中找到将动态类型转换回可用对象以检索扩展的TotalCount属性.
QueryHelper将执行查询
queryResult = Enumerable.ToList((dynamic)queryResult)
Run Code Online (Sandbox Code Playgroud)
但
request.Properties.TryGetValue("MS_InlineCount", out tmp)
Run Code Online (Sandbox Code Playgroud)
由于错误的底层对象而失败.
我的解决方案是在我的BreezeController中执行查询,并将行和TotalCount包装在一个数组中,就像Breeze一样.然后我可以将数组作为类型QueryResult传回,breeze将序列化为JSON到客户端.
public QueryResult Consignees(string filter, int skip, int take)
{
WcfService.Context context = new WcfService.Context(new System.Uri(System.Configuration.ConfigurationManager.AppSettings["URI"]));
//Main Table
System.Data.Services.Client.DataServiceQuery<WcfService.Consigne> qMain = context.Consignes.IncludeTotalCount();
//Projected Table
System.Data.Services.Client.DataServiceQuery<Consigne> qProj = (System.Data.Services.Client.DataServiceQuery<Consigne>)qMain
.Where(x => x.Refname.StartsWith(filter))
.Skip(skip)
.Take(take)
.Select(f => new Consigne { Refname = f.Refname, Consignee = f.Consignee, Address1 = f.Address1, Address2 = f.Address2, Address3 = f.Address3 });
System.Data.Services.Client.QueryOperationResponse<Consigne> qResult= qProj.Execute() as System.Data.Services.Client.QueryOperationResponse<Consigne>;
QueryResult queryResult = new QueryResult() { Results = qResult.ToList(), InlineCount = qResult.TotalCount };
return queryResult;
}
Run Code Online (Sandbox Code Playgroud)
通过使用Breeze .withParameters({...})子句将过滤条件作为简单参数传递,您获得了一些成功.您仍然可以使用orderBy,take,skip.
你需要使用WCF OData吗?你可以切换到更灵活的Web API吗?
假设我们在Docwind的Northwind世界中重新构想您的示例.为方便起见,您可以定义DTO类
public class ProductDto
{
public int ProductID { get; set; }
public string ProductName { get; set; }
}
严格来说,这不是必需的.但是你创建了这个类,所以你不必看到为你的投影生成的丑陋的匿名类型名称.
然后你添加一个这样的查询方法NorthwindController:
[HttpGet]
public IQueryable ProductDtos()
{
return _repository.Products
// TODO: move the following into the repository where it belongs
.Where(x => x.CategoryID == 1) // a surrogate for your 'Owner' filter
.Select(x => new ProductDto
{
ProductID = x.ProductID,
ProductName = x.ProductName
});
}
当您的客户端发出微风查询时,例如
var q = breeze.EntityQuery.from('ProductDtos')
.where('ProductName', 'startsWith', 'C')
.orderBy('ProductName')
.take(5);
// execute it
它解析为以下URL
http://localhost:47595/breeze/Northwind/ProductDtos?$filter=startswith(ProductName,'C') eq true&$orderby=ProductName&$top=5
并返回四个{ProductID,ProductName}对象.
如果您ProductDto在客户端元数据中描述,breeze会将这些对象视为实体并对其进行缓存.您将获得更改通知,更改跟踪,验证等.您可以将更改保存回服务器,在该beforeSaveEntities方法中,您可以验证它们并将它们转换回Product实体,以便EF可以将它们保存到数据库中.我不会在这个答案中详述,但我希望你知道你可以做到.
请注意,您只能按投影属性进行过滤,而不能按未公开的根类型中的属性进行过滤.例如,以下查询失败,因为Product.SupplierID它不在所选ProductDto属性中:
http://localhost:47595/breeze/Northwind/ProductDtos?$filter=SupplierID eq 18&$orderby=ProductName&$top=5
回应是
消息:"URI中指定的查询无效.",
ExceptionMessage:"类型'Northwind.Models.ProductDto'没有属性'SupplierID'.",
鉴于您对未公开属性的安全性问题,我假设您希望此查询失败.
但是,如果您确实需要按照某些不在投影类型中的条件进行过滤,则可以更改服务器方法以接受参数.例如:
[HttpGet]
public IQueryable ProductDtos(int? supplierID=null)
{
// TODO: move the following into the repository where it belongs
var query = _repository.Products
.Where(x => x.CategoryID == 1); // a surrogate for a security filter
if (supplierID != null)
{
query = query.Where(x => x.SupplierID == supplierID);
}
return query.Select(x => new ProductDto
{
ProductID = x.ProductID,
ProductName = x.ProductName
});
}
现在客户端可以写:
var q = breeze.EntityQuery.from('ProductDtos')
.withParameters( {supplierID: 18} ) // <-- passed as arg to the GET method
.where('ProductName', 'startsWith', 'C')
.orderBy('ProductName')
.take(5);
// execute it
哪个解决了
http://localhost:47595/breeze/Northwind/ProductDtos?$filter=startswith(ProductName,'C') eq true&$orderby=ProductName&$top=5&supplierID=18
结果是两个ProductDto传递所有过滤条件的对象.
ps:我不是这样说的.我尝试了这段代码并完全按照这个答案中的描述获得了这些结果.
| 归档时间: |
|
| 查看次数: |
917 次 |
| 最近记录: |