Adding an "Or" clause on the server for breeze query - breeze

So we want to be able to search for a person by their phone number. From this SO post I gather that adding a where clause through a navigation property that is a list doesn't work in breeze yet.
That is ok with me because breeze provides an awesome way to do server side properties. However when I write my query on the server I need the extra where clause to be added as an "OR" to the query so that is doesn't interfere with where clauses that I already have on the client. I am doing this on the server but it isnt working. (Note this is using the DevForce Predicate Builder):
var pred = PredicateBuilder.False<Person>();
pred.Or(x => x.PhoneNumbers.Any(y => y.Value.StartsWith(searchString)));
var qry = _contextProvider.Context.People.Where(pred);
Am I building the predicate wrong or is what I am doing being added as and "And" clause and thus interfering with my other where clauses from the client?

Updated post: 11/25/13
As of Breeze 1.4.6, 'any' and 'all' operators are now supported.
So your client side Breeze query would look something like:
var query = EntityQuery.from("People").where("PhoneNumbers", "any", "Value", "startsWith", searchString);
This assumes that you have a "People" endpoint that returns a person object that has a "PhoneNumbers" property that in turn has its own "Value" property.
Also see: http://www.breezejs.com/documentation/query-examples
Older post
Breeze does support or'ing predicates together as in:
var pred = Predicate.create("ShipCity", "stArtsWiTH", "F")
.or("ShipCity", "startswith", "C");
var q = EntityQuery.from("Orders").where(pred);
What breeze does not yet support are the 'any' and 'all' operators. Although these will be supported in the near future.

Related

Using navigation property in orderby clause of breeze query

I am using breeze to call a web api method which is:
Repository.ShipmentAppeals.Where(sa => sa.ShipmentID == shipmentID).Select(sa => sa.Appeal).Include("Case");
My breeze query looks like:
var query = EntityQuery.from('GetEditShipmentAppeals')
.withParameters({ shipmentID: shipmentID, caseID: caseID })
.orderByDesc("Case.ID")
GetEditShipmentAppeals is a web api method that contains the first query. In spite of using .Include("Case") in the query I am not able to use "Case.ID" in the order by clause of breeze query.
var query = EntityQuery.from('Appeals')
.expand("Case,Patient")
.orderByDesc("Case.ID").inlineCount();
Even if I use navigation property on a breeze query that does not involve a EF query in web api, it does not work. In above query Case is a navigation property in Appeal table.
If I understand your example correctly, then I think that this is an Entity Framework issue. My understanding is that Entity Framework does not support "Includes" on a projection. See http://connect.microsoft.com/VisualStudio/feedback/details/347543/entity-framework-eager-loading-not-working-in-some-projection-scenarios.
To confirm this, I would try executing your EF query in isolation and see if the "Include" is actually doing anything. My guess is that it isnt.
However, you can still accomplish what you want with a slightly different server side projection. ( I'm not sure what object 'Case' is a property of and the syntax may be a bit off but...) Something like:
Repository.ShipmentAppeals.Where(sa => sa.ShipmentID == shipmentID).Select(sa => new
{ Appeal: sa.Appeal, Case: sa.Appeal.Case, CaseId: sa.Appeal.Case.Id });
Note that Breeze will return a collection of 'anonymous' javascript objects from this query, but each of the 'entities' within each of these objects (i.e. Appeals and Cases) will be full Breeze entities and will be part of the EntityManager cache.

Query locally for objects with non-empty collection

I have a collection of objects called Parents (some without children yet), and a related collection of Children.
I have all parents and children cached locally. For certain views I want to show just those Parents who have children.
I'm having trouble figuring how to do this.
I've tried
breeze.EntityQuery
.from("Parents")
.where("Children", "!=", null)
This returns all Parents.
I've also tried
breeze.EntityQuery
.from("Children")
.select("Parents")
This returns duplicate parents for families with more than one child. In addition it returns simple objects, not breeze entities.
I've also tried
breeze.EntityQuery
.from("Parents")
.where("Children", "!=", [])
&
breeze.EntityQuery
.from("Parents")
.where("Children.length", ">", 0)
Is there a way to do this?
Thanks!
Updated post: 11/25/13
As of Breeze 1.4.6, 'any' and 'all' operators are now supported.
Older post
Breeze doesn't yet support 'any' and 'all' query operators, (which is what would allow this operation) but they are on our roadmap. Please vote for this on the Breeze User Voice.
If you only need to determine this locally then the easy workaround would probably be to just use this: ( untested code, so there might be typos).
// assuming "Parent" is the name of the entity type corresponding to the "Parents" endpoint
var parentEntitiesWithChildren = myEntityManager.getEntities("Parent").filter(function(parent) {
return parent.getProperty("Children").length > 0;
});

The method Distinct is not supported

I am using Linq to Entities and am getting this error
The method Distinct is not supported
On this line of code
var typeIds = _context.AttributeValues.Select(av => av.AttributeTypeId).Distinct();
Why is this?
As per MSDN few LINQ methods are not supported which using OData service. Below is a partial list of unsupported methods.
All
Any
Concat
DefaultIfEmpty
Distinct
Except
Intersect
Union
Zip
For a full list of unsupported operations see here
However, as a workaround following statement should work in this case.
var typeIds = _context.AttributeValues
.Select(av => av.AttributeTypeId)
.AsEnumerable()
.Distinct();
A solution is to define a WCF Data Service using (server-side) the QueryByCube method provided by my product AdaptiveLINQ (www.adaptivelinq.com). This method transforms a projection (expressed by the select operator) in an aggregation.
You have just to define a cube with one dimension : AttributeTypeId
av => av.AttributeTypeId
Define a Data Service providing the queryable collection:
yourDbContext.AttributeValues.QueryByCube(yourCube);
Now you can query your service using the OData protocol:
http://.../myService.svc/AttributeValues?$select=AttributeTypeId
Or, if your using a C# client:
serviceContext.AttributeValues.Select(x => x.AttributeTypeId);
The advantage of this solution relative to the workaround proposed A J Qarshi is that the distinction is made on the server side.

LINQ join in VB.NET return concrete type rather than anonymous

I have the following LINQ query in VB.NET
Using db As New ReablementLSQLDataContext
query = (From b In db.Visits
Join c In db.LinkStaffToVisits On b.ID Equals c.VisitID
Where c.StaffID = staffid And b.StartEpoch = newepochdatetime).ToList()
End Using
When I run this, it returns a list of type anonymous which means its pretty useless if I want to access any of the data in it. How do I run this join statement and return a list of a concrete type?
Anonymous types as query results aren't so "useless", since you can always foreach over them (locally). Still, if you want a concrete type, you can add a select statement at the end and project the anonymous result into your type (supposed that you made this type and know which fields to use where), like (C# syntax)
var newQuery = query.Select(anon_x => new YourType(anon_x.field1, anon_x.field2, ...))
You can use a generic version of ToList method. I am a C# developer and can provide syntax related to C# :
.ToList<YourType>();
For VB.Net version read : http://msdn.microsoft.com/en-us/library/bb342261.aspx#Y0

Entity SQL Sort Then LINQ to Entities GroupBy Doesn't Return IOrderedQueryable

Works: My UI sends up entity sql sort expressions from a jqGrid to my DAL and then applies some Where clauses that get returned to my service layer. My service layer will then create a PaginatedList object that applies the Skip()..Take() to the IQueryable.
Example:
var qry = ((IObjectContextAdapter)DbContext).ObjectContext
.CreateQuery<TEntity>(entityName)
.OrderBy(pEntitySQLSort.GetEntitySQL());
//GetEntitySQL() i.e. "it.WorksheetID ASC"
return qry.Where(p=> pStatus == "blah").Skip(5).Take(10);
Doesn't Work: Applying a GroupBy() then Select() that returns a list of the same type of entities (Worksheet).
Example:
var qry = ((IObjectContextAdapter)DbContext).ObjectContext
.CreateQuery<TEntity>(entityName)
.OrderBy(pEntitySQLSort.GetEntitySQL());
var qryGrouped = qry.GroupBy(pWorksheet => pWorksheet.ParticipantID)
.Select(pGroup => new {Group = pGroup, LatestWorksheetID = pGroup.Max(pWorksheet => pWorksheet.WorksheetID)})
.Select(p => p.Group.FirstOrDefault(pWorksheet => pWorksheet.WorksheetID == p.LatestWorksheetID));
return qryGrouped.Skip(5).Take(10); //throws exception.
Throws NotSupportedException: The method 'Skip' is only supported for sorted input in LINQ to Entities. The method 'OrderBy' must be called before the method 'Skip'.
It seems to me that the first snippet does return an IOrderedQueryable that applies the esql sorting expression but the second snippet does not? Or maybe does GroupBy() remove the ordering of a query/collection ? If this is is the case, and since esql must be applied BEFORE LINQ to Entities, how could I accomplish the sql sorting + LINQ GroupBy ?
Related:
When is ObjectQuery really an IOrderedQueryable?
Why can't we mix ESQL and LINQ TO Entities
GroupBy() returns an IGrouping<int, Worksheet>. The actual object is an ObjectQuery returned as IQueryable. You linked to my question (When is ObjectQuery really an IOrderedQueryable?), so you know that the fact that this ObjectQuery also implements IOrderedQueryable does not necessarily mean that it actually behaves as such.
In a more elementary, related, question, Jon Skeet made the distinction between actual type and compile-time type. The compile-time type (IQueryable) is what matters.
So, GroupBy effectively cancels the previous OrderBy. In a quick test on a similar case I could see that even the ordering is gone in the grouping. Conclusion: you'll have to re-apply an OrderBy for the Skip to be executed successfully.

Resources