Possible bug in breeze 1.4.14 - entity-framework

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.

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 })

Related

HTTP PATCH method in golang

I am implementing a HTTP PATCH method in golang and postgresql, I need to read the data from the request and update the data provided into the postgresql.
The method works fine if all the values of the struct is provided, but if only partial data is given to a request, the other fields are becoming empty. Can anyone please help me out to deal this problem.
type StudentDetails struct {
Id int `json:"id"`
Name string `json:"name"`
Age int `json:"age"`
Class int `json:"class"`
}
Query which I am using "UPDATE table_name SET name=$2, age=$3, class=$4 WHERE id=$1"
If all the fields given in the request this works fine, but if I need to update only the AGE and the request json would be {"age": 10} or some other field we dont know. Here Age is set to 10 but remaining all fields will become "" or 0 and that will be updated into the database
Anyone has the solution to this problem, how to update the requested field only and not change other fields.
I have approached using a separate query for all fields, but I think its not the proper one. Please give me a solution
Like what #David Hall said in the comments, use pointer to a type in the fields of your struct. See example below:
type ArticleModel struct {
gorm.Model
ID uuid.UUID `gorm:"primaryKey;type:uuid"`
Title *string
Body *string
}
I am using gorm, then when unmarshalling the json from http request you will get nil value if not provided. You need to add nil checkers to skip in the construction of your SQL query. Something like this.
if entity.Title != nil {
model.Title = entity.Title
}
if entity.Body != nil {
model.Body = entity.Body
}
db.Save(&model)
Now the next problem would be how to intentionally empty the field in database (explicitly nulling the value) like UPDATE table SET field = null. Unfortunately I haven't figured it out also.
What I have in mind is checking if empty string and considering it as the setting it to empty value. Although I want to see better options.

EF Core completely ignores my selected properties in select

As I understand it, the following code should generate a query containing only the RouteId, RouteNo, and ShipId
var tow = (from t in _context.AllTowData
where t.RouteId == id
orderby t.RouteNo descending
select new TowDefaults {
Id = t.RouteId,
TowNo = t.RouteNo,
ShipId = t.ShipId,
LastTow = t.RouteNo
})
.FirstOrDefault();
However, I get:
SELECT v.route_id, v.route_no, v.tow_id, v.analysis_complete, v.checks_complete, v.cpr_id, v.date_created, v.date_last_modified, v.factor, v.fromportname, v.instrument_data_file, v.instrument_id, v.internal_number, v.mastername, v.message, v.miles_per_division, v.month, v.number_of_samples, v.number_of_samples_analysed_fully, v.prop_setting, v.route_status, v.sampled_mileage, v.serial_no_per_calendar_month, v.ship_speed, v.silk_reading_end, v.silk_reading_start, v.toportname, v.tow_mileage, v.validity, v.year
FROM view_all_tow_data AS v
WHERE v.route_id = '#__id_0'
ORDER BY v.route_no DESC
LIMIT 1
That's every column except the explicitly requested ShipId! What am I doing wrong?
This happens using both a SQL Server and a PostGres database
The property ShipIdis not mapped, either by a [NotMapped] annotation or a mapping instruction. As far as EF is concerned, the property doesn't exist. This has two effects:
EF "notices" that there's an unknown part the final Select and it switches to client-side evaluation (because it's a final Select). Which means: it translates the query before the Select into SQL which doesn't contain the ShipId column, executes it, and materializes full AllTowData entities.
It evaluates the Select client-side and returns the requested TowDefaults objects in which ShipId has its default value, or any value you initialize in C# code, but nothing from the database.
You can verify this by checking _context.AllTowData.Local after the query: it will contain all AllTowData entities that pass the filter.
From your question it's impossible to tell what you should do. Maybe you can map the property to a column in the view. If not, you should remove it from the LINQ query. Using it in LINQ anywhere but in a final Select will cause a runtime exception.

Comparing ObjectID's in Jade and MongoDB

Jade Template Code
each member in team.members
if member == user._id
- flag=true;
Here, team is a document in the collection 'teams' in Mongo DB, and 'members' is a property having Arrays as value.
Here values of #{member} are 53fecc27bace957811633dcc and 5412a08fa51c105017b9f1fe respectively. Both are Object Id's.
Value of #{user.id} is 53fecc27bace957811633dcc
However, this comparison returns as false and flag is never set to true.
Why is it so?
EDITED FOR CLARITY:
The mongodb-native driver uses a custom ObjectID type. Even if the ObjectIDs are the same, member and user._id would still refer to two distinct objects, and therefore the comparison fails.
Here's a simplified example of what I'm talking about. In the example below I have a constructor function for a TestObject (simulating the mongo ObjectID). I instantiate two objects (i.e. x1 and x2) both with the same parameter. While x1 and x2 are instances of the same object and both were created with the same arguments, they are actually just two different objects with the same data/payload. Therefore, the first direct comparison fails, because they in fact are not the same. To take the simulation a bit further, I added a prototype method .equals() which ensures that both objects are instances of TestObject and the payloads are identical.
function TestObject(data) {
this.payload = data;
}
TestObject.prototype.equals = function(anotherObject) {
return (anotherObject instanceof TestObject) && (this.payload === anotherObject.payload);
};
var x1 = new TestObject(1), x2 = new TestObject(1);
console.log(x1 == x2); // <-- false
console.log(x1.equals(x2)); // <-- true
You can compare them by converting the ObjectIDs to strings.
each member in team.members
if member.toString() == user._id.toString()
- flag=true;
Another possible solution would be to use the ObjectId .equal() method:
each member in team.members
if member.equals(user._id)
- flag=true;
MongoDB objectIds are probably not simple strings. As per docs, they are BSON types.
It's possible that member and user._id are two different objects that is why a "reference equals" comparison is failing, even though their string representations are the same.
On a related note, it's a bad idea to use MongoDB generated object IDs in your application. A more robust design would be to have your own identifier for every record type.

Breeze: Unable to locate property: XYZ on type:YYY when executing executeQuery on entity manager

I'm trying to get data from my Webapi2 Breeze controller with Entity Framework 6 and .NET 4.5.1. And get the error "unable to locate property" when I use the Where clause on a navigation property. The call is not even made to the Webapi2 Controller
If I leave out the where clause, the data is returned correctly.
The relevant part of the c# class:
public class NotificationRule {
public Guid NotificationRuleId { get; set; }
public virtual NotificationRuleSet NotificationRuleSet { get; set; }
}
The relevant part of the C# class in the navigational property NotificationRuleSet:
public class NotificationRuleSet{
public Guid NotificationRuleSetId { get; set; }
public virtual List<NotificationRule> NotificationRules { get; set; }
}
The relevant part of the C# Breeze controller:
public IQueryable<NotificationRuleSet> NotificationRuleSets()
{
return _contextProvider.Context.NotificationRuleSets;
}
public IQueryable<NotificationRule> NotificationRules()
{
return _contextProvider.Context.NotificationRules;
}
The relevant part of the 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"));
If I leave the Where clause out, the data is transferred correctly as you can see in this Fiddler dump:
{
"$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"
}
],
},
}
So I get an error that a property does not exists, but it seems to exists.
Using a Where on a non navigational property works fine.
I've read something about camelCasing but replacing NotificationRuleSet with notificationRuleSet gives the same error.
EDIT:
The solutions seems to be that NotificationRules in the Viewmodels query should start with a lowercase character, regardless wether the first character of the controllers method name is upper or lowercase .
camelCasing is most likely your issue provided both the entity and property do exist -
.where('notificationRuleSet.notificationRuleSetId', "==", this.NotificationRuleSetId)
Remember that when you are camelCasing your property names it is for the navigation property as well.
I thought I had an explanation after reviewing you interaction with PW Kad.
My guess was that the ACTUAL defaultResourceName for your NotificationRule type is "notificationRules".
Can you tell me what it is? The following expression will reveal it:
manager.metadataStore.getEntityType('NotificationRule').defaultResourceName;
Another question. You say it fails. What is the failure exception (check the payload of the response). Is it something like this?
$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",
Here is what I was thinking. Most of the time, Breeze doesn't need to know the root type of a query when that query is sent to the server. It can simply wait for the query results and reason over the JSON to determine the type (or types) involved.
But the occasional query involves a filter comparison that is ambiguous in its data type. GUIDs are a good example. Unless breeze knows the query root type it can't know for sure if the "11111111-be1e-423c-ac5b-f2c689093aca" in "foo == '11111111-be1e-423c-ac5b-f2c689093aca'" should be a string or a GUID. A human would guess it's a GUID; Breeze is not so sure. You can be sure only if you know the datatype of the "foo" property.
Breeze will compose the query anyway. If it guesses string if produces a URL that looks like "...foo eq '11111111-be1e-423c-ac5b-f2c689093aca'..." and that will fail (for me anyway).
I thought this could be your issue.
I tried an experiment in DocCode that I thought would demonstrate it. I changed the endpoint name for an Order query to something that is NOT the Order type's defaultResourceName(which is "Orders").
As it happens, Web API doesn't care if the URL says 'orders' or 'Orders' so I can achieve my goal of confusing Breeze about the root type by pointing the query to "orders" and the query should still be routed by Web API to the proper controller GET method.
I was expecting that Breeze would compose the GUID query as a string and thus I could duplicate your issue. Here is my attempt
/*********************************************************
* 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);
});
Unfortunately, the test passes!
This is the URL that Breeze sent to the server:
http://localhost:56337/breeze/Northwind/orders?$filter=Customer.CustomerID eq guid'785efa04-cbf2-4dd7-a7de-083ee17b6ad2'&$expand=Customer
DAMN Breeze (v.1.4.12) was too smart for me. It somehow figured out that my comparison value is a GUID ... despite not knowing the root type of the query.
That means I do not have an explanation for why, in your example, breeze.EntityQuery.from("notificationRules") works but breeze.EntityQuery.from("NotificationRules") does not.
Maybe I'll have another idea once you tell us the defaultResourceName AND show us the URLs that are generated (a) when it works and (b) when it does not work.

Using max() function with entity framework throws an exception

So I need to get the max value of a column (or the last one) using entity framework and both of these queries throw exceptions:
(The ID I'm trying to retrieve is of type varchar, but it works in raw sql, I think
it should work here too)
This one:
string maxCurrentID = db.reservations.Max().ReservationID;
Throws this:
The specified method 'EntityClub_.reservacion Maxreservacion' on the type 'System.Linq.Queryable' cannot be translated into a LINQ to Entities store expression because no overload matches the passed arguments.
and this one:
string maxCurrentID = db.reservations.LastOrDefault().ReservationID;
LINQ to Entities does not recognize the method 'EntityClub_.reservacion LastOrDefaultreservacion' method, and this method cannot be translated into a store expression.
How can I obtain the expected values?
var maxReservationId=db.reservations.Max(u =>(int?)u.ReservationID) ?? 0;
if there is no data in table it replaces null with 0
You aren't asking for the highest ReservationID, you're trying to get the highest Reservation, and getting its ReservationID. EF does not understand what "the highest Reservation" means.
var maxReservationID = db.reservations.Max(r => r.ReservationID);
or
var maxReservationID = db.reservations.Select(r => r.ReservationID).Max();
should work.