我在我的项目中使用angular,breeze,WebApi,EF,SqlServer2008。 我有表文章和表格ArticleComments,所以一篇文章可以有很多文章评论记录。
public class Article{
public int ArticleId { get; set; }
public string ArticleName { get; set; }
public string Description { get; set; }
public ICollection<ArticleComment> Comments { get; set; }
public ICollection<ArticleImage> ImagesList { get; set; }
...
}
public class ArticleComment
{
public int ArticleCommentId { get; set; }
public string CommentText { get; set; }
public int UserId { get; set; }
public int Rate { get; set; }
public DateTime CommentDate { get; set; }
public int ArticleId { get; set; }
public Article Article { get; set; }
public int Status { get; set; }
}
在客户端我需要获得带有评论,图片和其他链接实体的完整文章实体,但评论只需要选择的文章记录和字段&#34; status&#34; == 1.
我尝试使用此类查询
var pred = breeze.Predicate.create('articleId', 'eq', id)
.and('comments', 'any', 'status', '==', 1);
return EntityQuery.from("Articles")
.where(pred)
.expand('comments, imagesList...')
.toType(entityNames.article)
.using(manager).execute()
.to$q(querySucceded, self._queryFailed);
这将返回文章的所有注释,但不会按状态字段过滤扩展的表ArticleComments。
答案 0 :(得分:2)
杰里米是对的。这是一个长期存在的EF疼痛。由于OData不支持过滤expand
的方法,因此没有做得更好。
您可以使用投影在服务器端执行您想要的操作。我在DocCode示例中使用了这个想法。
我向NorthwindRepository
添加了一个新的CustomersAnd1998Orders
方法,该方法在NorthwindController
这是一个完全可查询的端点。它返回的是客户以及1998年订购的订单。奇怪的是,它返回的JSON类型为CustomerDto
而不是Customer
。您必须针对那些使用客户端查询进行调整...我将在下面解释。
我不知道为什么要这样做。如果我投射到
Customer
,我会从EF获得运行时异常。
这里是`NorthwindRepositoryCustomersAnd1998Orders:
private class CustomerDto : Customer { } // EF requires a shadow class to make the LINQ query work
public IQueryable<Customer> CustomersAnd1998Orders {
get
{
return ForCurrentUser(Context.Customers)
.Select(c => new CustomerDto {
CustomerID = c.CustomerID,
CompanyName = c.CompanyName,
ContactName = c.ContactName,
ContactTitle = c.ContactTitle,
Address = c.Address,
City = c.City,
Region = c.Region,
PostalCode = c.PostalCode,
Country = c.Country,
Phone = c.Phone,
Fax = c.Fax,
RowVersion = c.RowVersion,
Orders = c.Orders
.Where(o => o.OrderDate != null && o.OrderDate.Value.Year == 1998)
.ToList()
});
}
}
有点乏味但如果你需要它,你需要它。
&#39; Orders&#39;上的过滤器选择1998年订购的订单(这是旧的Northwind数据)。 OrderDate
为nullable<DateTime>
,因此我们必须检查null
,然后将年份从Value
中拉出来。
请注意,它使用.Select
子句投射到CustomerDto
,私有,&#34;无所事事&#34; Customer
的子类,所以我在技术上返回IQueryable<CustomerDto>
。但它确实有效。
NorthwindController.NorthwindRepositoryCustomersAnd1998Orders
没有任何背叛:
[HttpGet]
public IQueryable<Customer> CustomersAnd1998Orders() {
return _repository.CustomersAnd1998Orders;
}
在Breeze客户端上查询,就像客户&#39;但没有指定.expand
条款;服务器将负责处理。
有一个转折点。看看您是否可以在this test from DocCode中找到它:
var query = EntityQuery.from('CustomersAnd1998Orders')
.where('CompanyName', 'startsWith', 'C')
.orderBy("CompanyName")
.toType('Customer'); // Essential ... unless fix with a JsonResultsAdapter
verifyQuery(newEm, query,
"Customers from 'CustomersAnd1998Orders' projection",
showCompanyNamesAndOrderCounts,
assertCustomersInCache,
assertOrdersInCache,
assertAllOrdersIn1998);
烨。您必须将结果转换为Customer
,因为线上的类型是&#34; CustomerDto&#34;
$type: "DocCode.DataAccess.NorthwindRepository+CustomerDto, DocCode.DataAccess.EF"
但至少你可以在数据层上过滤(.where()
)和排序(orderBy()
)和页面(take()
和skip()
)。
对我来说这个结果要付出很小的代价?
答案 1 :(得分:1)
实体框架在使用&#34; .Include(...)&#34;时不支持过滤。这就是微风&#34; .expand(...)&#34;转换为服务器。类似问题已发布here和here。
您当前的查询是:
只要至少有一篇文章,请给我带articleId == id的文章 评论状态== 1。包括所有评论和图片。
我相信你想要表达的是:
给我带articleId == id的文章。包括状态== 1的评论 以及它所有的图像。
我不知道在一个查询中表达这种情况的方法,除非您创建一个类似Jay所描述的专用控制器操作here。
或者你也可以这样做:
var pred = breeze.Predicate.create('articleId', 'eq', id);
return EntityQuery.from("Articles")
.where(pred)
.expand('comments, imagesList')
.toType(entityNames.article)
.using(manager)
.execute()
.to$q(
function(result) {
// detach all comments whose status!=1
var commentType = manager.metadataStore.getEntityType(entityNames.articleComment),
comments = manager.getEntities(commentType)
.filter(function(comment) { return comment.status !== 1; });
comments.forEach(manager.detachEntity);
querySucceded(result);
},
self._queryFailed);
这种方法的优点是它不需要服务器端修改。缺点是它会加载超出您需要的评论,并强迫您在之后将其分离到客户端。
第三种方法是发出两个查询:一个用于加载文章及其imageList,另一个用于加载其articleId == id和status == 1的注释。要执行此操作,您需要在控制器中执行一个返回IQueryable<ArticleComment>
的操作。这种方法的缺点是您需要发出两个http请求。你可以并行完成这些并且随着spdy的出现,从长远来看这可能不是什么大问题。