Open EchoFoxxtrot opened 1 year ago
Not a bug.
In this case, you need to use some additional syntax to indicate whether you are querying the literal value or the property.
// query where the Title property starts with the Area property
let propertyPredicate = new Predicate('Title', FilterQueryOp.startsWith, { value: 'area', isProperty: true });
// query where the Title property starts with the literal 'area'
let valuePredicate = new Predicate('Title', FilterQueryOp.startsWith, { value: 'area', isProperty: false });
This is in the Breeze documentation, but it's buried pretty deep.
I attempted to fix this issue in my own application by using isProperty: false
, but now my queries that are not string based queries are all failing. I also tried isLiteral: true
but that had the same effect.
Can you give me an example of a query that is failing, and what the error is?
Sorry, I've already made a workaround: to test the value I wanted to query by and only apply isProperty: false
when the value is a string type and not a date formatted string. This fixed the data type errors we were seeing (could not filter Int32 by Double, etc.) For background, all the data tables uses a single architecture to send these queries to our back-end. A user happened to filter a string column by a value that happened to also be a property name on the same entity. This causes issues when both are strings and the behaviour is not expected. The other and worse thing that happened was if you searched by a property name that was a different data type completely (string could not be filtered by Int32 is the sort of error we saw).
I was hoping isProperty: false
simply disabled making the query search by another property in the filter, but it had other unwanted side-effects aforementioned.
Sorry I don't have more expertise. I've just taken over this project and never heard of Breeze :) In code, my workaround was to do this:
// don't accidentally attempt to query by another property name because it's ambiguous behavior
// if the value is a string and not a date formatted string, then set isProperty: false
// we can't always set isProperty: false because the query sends the wrong data type to the server for some reason.
let queryValue = typeof value !== "string" || /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d*)?Z?$/.test(value) ? value : { value, isProperty: false };
...
let result = new Predicate(_this.fixFieldName(criteria[0]), translateBinaryOperator(operator), queryValue);
Please help me, because I'm trying to reproduce the scenario in the Breeze tests.
Let's say I have an entity with three properties, stringProp
, intProp
, and dateProp
, which are type string
, Int32
, and DateTime
respectively. What do I do to get the "could not filter Int32 by Double" and "string could not be filtered by Int32" errors?
Also, what version of Breeze are you using on the client and the server?
The server is using Breeze.AspNetCore.NetCore (6.0.4)
and the client is using breeze-client: ^2.1.2
In my scenario this Predicate
caused the error I mentioned:
new Predicate("intProp", "eq", { value: 1, isProperty: false }); // it was passing Data Type: Double to the server instead of `Int32` or whatever it should have been passign
This worked fine
new Predicate("intProp", "eq", 1);
Something about setting that flag caused the query to be built incorrectly. As I mentioned, I have little to no experience with Breeze, just enough to make a workaround for the filtering by property name issue the OP mentioned (I understand there are circumstances where it would be appropriate to have that behavior).
If you can't recreate it in your tests, I'm sure something in the architecture of this project is to blame. Thank you for being a good steward of this project.
The "string couldn't be filtered by Int32" error was caused by this predicate:
new Predicate("stringProp", "eq", "intProp");
This fixed that issue (because I didn't want to filter by the actual property value, I wanted to filter by the literal string....
new Predicate("stringProp", "eq", { value: "intProp", isProperty: false });
I was hoping I could just always set isProperty: false
but as mentioned, that had side-effects in my project
Thanks for the help. I'll see if I can fix it. I'm glad you found the workaround for you.
I could not reproduce the problem.
The data type of a property -- String, Int32, Double, etc. -- comes from the Breeze metadata, which is consumed by the Breeze EntityManager and usually generated based on the server classes. Your metadata may need updating or correcting.
You can also specify the data type explicitly in the predicate:
new Predicate("intProp", "eq", { value: 1, isProperty: false, dataType: "Int32" });
Consider the following scenario:
I have an entity type called Area that corresponds to an Area table in my database and I have another entity type in the same entity metadata set that contains a Title field, defined as a string, that I want to query against by creating a Predicate something like the following:
I then use my predicate with the EntityQuery.where() method to query my other table which DOES NOT have a field or navigation property called "Area".
The result is that I will receive an error from the EntityManager that states:
This is true when you write any Predicate using any valid FilterQueryOp operator to query for any string that is an exact caseless match of the name of any Entity Type that is registered from a server Metadata call on an Entity Framework Core dbContext.
My current workaround to this is to remove the last character of a "startsWith" predicate or the first character of an "endsWith" predicate, but it gets dicey when I need to use an "equals" predicate, so it would be nice if this bug could be fixed.