Breeze:无法定位属性:XYZ on type:YYY在实体管理器上执行executeQuery时

时间:2014-05-12 14:02:37

标签: entity-framework breeze asp.net-web-api2

我正在尝试使用Entity Framework 6和.NET 4.5.1从我的Webapi2 Breeze控制器获取数据。当我在导航属性上使用Where子句时,得到错误“无法找到属性”。甚至没有对Webapi2控制器进行调用

如果我省略了where子句,则会正确返回数据。

c#类的相关部分:

public class NotificationRule {
    public Guid NotificationRuleId { get; set; }
    public virtual NotificationRuleSet NotificationRuleSet { get; set; }
}

导航属性NotificationRuleSet中的C#类的相关部分:

public class NotificationRuleSet{
    public Guid NotificationRuleSetId { get; set; }
    public virtual List<NotificationRule> NotificationRules { get; set; }
}

C#Breeze控制器的相关部分:

    public IQueryable<NotificationRuleSet> NotificationRuleSets()
    {
        return _contextProvider.Context.NotificationRuleSets;
    }

    public IQueryable<NotificationRule> NotificationRules()
    {
        return _contextProvider.Context.NotificationRules;
    }

Query(Typescript)的相关部分:

            var query = breeze.EntityQuery.from("NotificationRules")
                .where ("NotificationRuleSet.NotificationRuleSetId","==", this.NotificationRuleSetId)
                .expand("NotificationRuleSet");


            var Result = this.BreezeEntityManager
                .executeQuery(query)
                .then((data) => this.RefreshViewModelCallback(data))
                .fail((data) => alert("Fail to retrieve data"));

如果我将Where子句退出,正如您在此Fiddler转储中看到的那样正确传输数据:

{
    "$id": "1",
    "$type": "Imp.Classes.NotificationRule, Imp",
    "NotificationRuleId": "11111111-be1e-423c-ac5b-f2c689093aca",
    "NotificationRuleSet": {
        "$id": "2",
        "$type": "Imp.Classes.NotificationRuleSet, Imp",
        "NotificationRuleSetId": "11111111-1bd6-4520-9f69-381504b8e2b2",
        "NotificationRules": [
            {
                "$ref": "1"
            }
        ],
    },
 }

所以我收到一个错误,即属性不存在,但似乎存在。

在非导航属性上使用Where可以正常工作。

我读过有关camelCasing的内容,但用notificationRuleSet替换NotificationRuleSet会产生同样的错误。

编辑: 解决方案似乎是Viewmodels查询中的NotificationRules应该以小写字符开头,无论控制器方法名称的第一个字符是大写还是小写。

2 个答案:

答案 0 :(得分:2)

camelCasing很可能是你的问题,只要实体和财产都存在 -

.where('notificationRuleSet.notificationRuleSetId', "==", this.NotificationRuleSetId)

请记住,当您来自CamelCasing您的属性名称时,它也适用于导航属性。

答案 1 :(得分:0)

我认为在审核了你与PW Kad的互动后我得到了解释。

我的猜测是defaultResourceName类型的实际NotificationRule是&#34; notificationRules&#34;。

你能告诉我它是什么吗?以下表达式将揭示它:

manager.metadataStore.getEntityType('NotificationRule').defaultResourceName;

另一个问题。你说它失败了。什么是失败异常(检查响应的有效负载)。是这样的吗?

$id: "1",
$type: "System.Web.Http.HttpError, System.Web.Http",
Message: "The query specified in the URI is not valid.",
ExceptionMessage: "A binary operator with incompatible types was detected. Found operand types 'Edm.Guid' and 'Edm.String' for operator kind 'Equal'.",
ExceptionType: "Microsoft.Data.OData.ODataException",

这就是我的想法。大多数时候,当查询发送到服务器时,Breeze不需要知道查询的根类型。它可以简单地等待查询结果并通过JSON推断来确定所涉及的类型(或类型)。

但偶尔的查询涉及过滤器比较,其数据类型不明确。 GUID就是一个很好的例子。除非breeze知道查询根类型,否则它无法确定&#34; 11111111-be1e-423c-ac5b-f2c689093aca&#34;在&#34; foo ==&#39; 11111111-be1e-423c-ac5b-f2c689093aca&#39;&#34;应该是字符串或GUID。一个人会猜测它是一个GUID;微风不太确定。只有当你知道&#34; foo&#34;的数据类型时才能确定。属性。

Breeze无论如何都会撰写查询。如果它猜到字符串,如果产生一个看起来像&#34; ... foo eq&#39; 11111111-be1e-423c-ac5b-f2c689093aca&#39; ...&#34;这将失败(无论如何)。

我认为这可能是你的问题。

我在DocCode中尝试了一个我认为可以演示它的实验。我将订单查询的端点名称更改为不是Order类型的defaultResourceName(即&#34;订单&#34;)。

实际上,如果网址显示“订单”,则Web API并不关心。或者&#39;订单&#39;所以我可以通过将查询指向&#34; orders&#34;来实现我的目标,即将Breeze与根类型混淆。并且查询仍应由Web API路由到适当的控制器GET方法。

我原以为Breeze会将GUID查询组成一个字符串,因此我可以复制你的问题。这是我的尝试

/*********************************************************
* Orders of Customers with Alfred's ID
* Customer is the related parent of Order
* CustomerID is a GUID
* Demonstrates "nested query", filtering on a related entity
* where the filter criteria is ambiguous (string or GUID)
* and only knowing the root query type (Order) can disambiguate.
* The 'defaultResourceName' for Order is "Orders", not "orders"
* so I expect this test to fail ... but it doesn't ...
* because Breeze disambiguated anyway. 
*********************************************************/
test("orders of Customers w/ Alfred's ID (resource name is lowercased)", 2, function () {

    var query = EntityQuery.from("orders")
        .where("Customer.CustomerID", "==", testFns.wellKnownData.alfredsID)
        .expand("Customer");

    verifyQuery(newEm, query, "orders query", showOrdersToAlfred);
});

不幸的是,测试通过了!

这是Breeze发送给服务器的URL:

http://localhost:56337/breeze/Northwind/orders?$filter=Customer.CustomerID eq guid'785efa04-cbf2-4dd7-a7de-083ee17b6ad2'&$expand=Customer

DAMN Breeze(v.1.4.12)对我来说太聪明了。它以某种方式弄清楚我的比较值是一个GUID ...尽管不知道查询的根类型。

这意味着我没有解释为什么在您的示例中,breeze.EntityQuery.from("notificationRules")有效但breeze.EntityQuery.from("NotificationRules")没有。


一旦你告诉我们defaultResourceName并向我们展示生成的网址(a)何时起作用,以及(b)何时不起作用,我可能会有另一个想法。