Search code examples
entity-frameworkodatabreezeasp.net-web-api

Possible bug in breeze 1.4.14


I haven't tested this against the 1.4.16 release that came out a couple of weeks ago but there is nothing in the release notes about it.

The problem occurs with predicates where the value you are comparing is identical to the name of a property on any entity that breeze knows about. A simple test case is :

var query = breeze.EntityQuery.from('Items');

var pred = breeze.Predicate.create('name', breeze.FilterQueryOp.Contains, searchTerm);

query = query.where(pred);

Where searchTerm is equal to any string other than "name" this produces an oData query as below:

Items?$filter=(substringof(%27somevalue%27%2CName)%20eq%20true)

but if searchTerm = "name" then it produces the following query

Items?$filter=(substringof(Name%2CName)%20eq%20true)

Which istead of comparing the string 'name' against the property Name, it compares the property Name with itself.

I have not tested every operator but as far as I can tell it does not matter which you use you get the same behaviour.

You also get the same problem when querying navigation properties but it usually results in an invalid query. Below is a predicate for the same entity but against a navigation property tags that contains a collection of ItemTag entities that have a "Tag" property on them.

breeze.Predicate.create('tags', breeze.filterQueryOp.Any, 'tag', breeze.filterQueryOp.Contains, searchTerm)

It works fine for any searchTerm other than "tag" where it produces an oData request as below:

Items?$filter=Tags%2Fany(x1%3A%20substringof(%27somevalue%27%2Cx1%2FTag)%20eq%20true)

but if the searchTerm is "tag" then it requests:

Items?$filter=Tags%2Fany(x1%3A%20substringof(Tag%2Cx1%2FTag)%20eq%20true) 

which produces an error of "Could not find a property named 'Tag' on type 'Item'" because the property Tag exists on the ItemTag entity.

In short breeze seems to infer that any search term that is identical to the name of a property it knows about, refers to that property rather than being a string literal value.

Has anyone else encountered this?

Is this a bug, or is there a way to explicitly tell breeze to interpret that value as a string literal and not a reference to a property?

I am not sure it is relevant as the server seems to be responding correctly to the requests and it is breeze that is creating incorrect requests but on the server side I am using Web API oData controllers with EF as ORM data layer.


Solution

  • Try

    var pred = breeze.Predicate.create('name', breeze.FilterQueryOp.Contains, 
     { value: searchTerm, isLiteral: true} );
    

    This is described here ( under the explanation of the value parameter): http://www.breezejs.com/sites/all/apidocs/classes/Predicate.html#method_create

    if the value can be interpreted as a property expression it will be, otherwise it will be treated as a literal. In most cases this works well, but you can also force the interpretation by making the value argument itself an object with a 'value' property and an 'isLiteral' property set to either true or false. Breeze also tries to infer the dataType of any literal based on context, if this fails you can force this inference by making the value argument an object with a 'value' property and a 'dataType'property set to one of the breeze.DataType enumeration instances.

    The reason for this logic is to allow expressions where both sides of the expression are properties. For example to query for employees with the same first and last name you'd do this:

    var q = EntityQuery.from("Employees")
            .where("lastName", "==", "firstName");
    

    whereas if you wanted employees with a lastName of 'firstName' you'd do this:

    var q = EntityQuery.from("Employees")
            .where("lastName", "startsWith", { value: "firstName", isLiteral: true })