我有一个由EF代码优先创建的数据库,其中有两个主要类:'类别'和:'产品'。
每个类别都有一个产品列表的导航属性(与该类别相关的产品)。
我创建了一个web api,返回'IQueryable' - 所有与特定类别相关的产品。
这是api控制器 - 通过url调用时效果很好:
[HttpGet]
public IQueryable<Product> ProductsFilteredByCategory(int categoryId)
{
return _contextProvider.Context.Categories.Include("Products").First(c => c.CategoryId == categoryId).Products.AsQueryable();
}
然而,当我通过以下功能从微风拨打电话时:
var getProducts = function (productsObservable, parentCategoryId) {
var query = EntityQuery.from("ProductsFilteredByCategory")
.withParameters({ categoryId: parentCategoryId });
return manager.executeQuery(query)
.then(querySucceeded)
.fail(queryFailed);
}
我收到以下错误:'undefined不是函数'。
奇怪的是,当我更改服务器端的控制器以返回所有产品的简单'IQyeryable'列表时 - 没有错误......但这不是我需要的 - 我只需要那些相关的产品具有特定类别......
感谢您的帮助!
Elior
答案 0 :(得分:1)
你不必在你的控制器方法中使用这个参数,你可以删除参数并在你的breeze实体查询中用.where()声明它这样做的好处是你的控制器没有如此具体。
此外,您不需要使用.include(),因为breeze允许您使用.expand()扩展导航属性
这可以充分利用微风可以帮助您在项目中提供的帮助。
将ProductsFilteredByCategory(int categoryId)更改为
Public IQueryable<Product> Products()
{
return _contextProvider.Context.Products();
}
你的微风查询
var query = EntityQuery.from('Products')
.where('categoryId', '==', categoryId)
.expand('Category');
如果您不想这样做,那么我认为您需要重做控制器方法。您应该返回产品实体,但是您要查询类别。
答案 1 :(得分:0)
非常感谢你们的支持,我很感激。
Kadumel,我无法使用您的解决方案,因为每个“产品”都可以属于多个“类别”,因此“产品”和“类别”没有参考形式。但是,我确实按照你的建议更改了控制器方法,现在情况正常。
这是代表所有内容的代码,希望它也可以帮助处于类似情况的其他人。我很乐意听到并提出改进代码的建议。
public class Category
{
[Key]
public int CategoryId { get; set; }
[Required]
public string Name { get; set; }
public Int16? Order { get; set; }
[ForeignKey("ParentCategoryId")]
public Category ParentCategory { get; set; }
public int? ParentCategoryId { get; set; }
[ForeignKey("ParentCategory")]
[InverseProperty("ParentCategory")]
public List<Category> SubCategories { get; set; }
[ForeignKey("ProductId")]
public List<Product> Products { get; set; }
}
public class Product
{
[Key]
public int ProductId { get; set; }
[Required]
public string Name { get; set; }
public string Desc { get; set; }
public int Price { get; set; }
//[ForeignKey("CategoryId")]
//[InverseProperty("Products")]
//public List<Category> Categories { get; set; }
}
(正如您所看到的,我注释了从“产品”到“类别”的向后链接列表,这些链接可能被用作从“产品”到“类别”的向后引用,因为Kdumel建议我使用这些链接,但是在我看来,如果没有它们,有这么多的参考文件太“重要”,你同意吗?)
这是控制器中的代码:
[HttpGet]
public IQueryable<Category> CategoryWithProducts(int categoryId)
{
return _contextProvider.Context.Categories.Include("Products").Where(c => c.CategoryId == categoryId);
}
这是微风代码:
var getProducts = function (productsObservable, parentCategoryId) {
var query = EntityQuery.from("CategoryWithProducts")
.withParameters( {categoryId: parentCategoryId } )
.select("Products");
return manager.executeQuery(query)
.then(querySucceeded)
.fail(queryFailed);
function querySucceeded(data) {
if (productsObservable) {
productsObservable(data.results[0].products);
}
log('Retrieved [Products] from remote data source',
data, true);
}
};
正如您所看到的,结果是一个“类别”,我从中检索'querySuccedded()'函数中的'products'。
这有效,但我希望使用一种不起作用的不同方法:而不是传递'parentCategoryId'我尝试传递实际对象而不是ID作为'parentCategoryObj',然后我想到使用以下在不明确调用breeze控制器的情况下加载'products'导航属性的行:
parentCategoryObj.entityAspect.loadNavigationProperty("products")
但是,这导致没有加载“产品”,就像导航属性为null一样。奇怪的是,当我在这一行中将“products”改为“subCategories”时,只是为了检查导航属性是否是问题 - 'subCategories'数据已正确加载。我不明白为什么一个导航属性与另一个导航属性的行为不同(都是列表)。我更多地了解了这一点并注意到目前Breeze不支持“多对多”关系,我认为这就是原因,我是对的吗?...
再次感谢你们,知道好人愿意为你们提供帮助!
Elior