0

我有一个由 EF 代码优先创建的数据库,其中有两个主要类:“类别”和:“产品”。

每个类别都有一个产品列表(与该类别关联的产品)的导航属性。

我创建了一个返回“IQueryable”的 Web api——与特定类别相关的所有产品。

这是 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);

} 

我收到以下错误:“未定义不是函数”。

奇怪的是,当我更改服务器端的控制器以仅返回所有产品的简单“IQyeryable”列表时 - 没有错误......但这不是我需要的 - 我只需要那些与特定产品相关联的产品类别...

谢谢你的帮助 !

埃利尔

4

2 回答 2

1

您不必在控制器方法中使用参数,您可以删除参数并使用 .where() 在微风实体查询中声明它,这样做的好处是您的控制器不必如此具体的。

此外,您不需要使用 .include(),因为微风允许您使用 .expand() 扩展导航属性

这充分利用了微风可以在您的项目中为您提供的更多帮助。

将 ProductsFilteredByCategory(int categoryId) 更改为

Public IQueryable<Product> Products()
{
    return _contextProvider.Context.Products();
}

和你的微风查询

var query = EntityQuery.from('Products')
       .where('categoryId', '==', categoryId)
       .expand('Category');

如果您不想这样做,那么我认为您需要重做控制器方法。您应该返回 Product 实体,但您正在查询类别。

于 2013-06-10T14:16:52.720 回答
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; }
}

(如您所见,我注释掉了从 'Product' 到 'Category' 的反向链接列表,这本可以用作从 'Product' 到 'Category' 的反向引用,因为 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()”函数中的“产品”。

这行得通,但我希望使用另一种不起作用的方法:我没有传递“parentCategoryId”,而是尝试将实际对象而不是 ID 作为“parentCategoryObj”传递,然后我想到使用以下行来加载没有显式调用微风控制器的“产品”导航属性:

parentCategoryObj.entityAspect.loadNavigationProperty("products")

但是,这导致没有加载任何“产品”,就好像导航属性为空一样。奇怪的是,当我在这一行中将“产品”一词更改为“子类别”只是为了检查导航属性是否存在问题时——“子类别”数据已正确加载。我不明白为什么一个导航属性的行为与另一个不同(两者都是列表)。我阅读了更多关于此的内容并注意到当前 Breeze 不支持“多对多”关系,我认为这就是原因,对吗?...

再次感谢你们,知道好人愿意提供帮助是一种解脱!

埃利尔

于 2013-06-11T05:50:38.700 回答