Using Linq to filter parents by their children - silverlight

Having some problems with my Silverlight app (with RIA services) filtering my results. The idea is on the client I set up the EntityQuery and its filters and call load. However this isn't working for me.
Heres my code.
public void FireQuery(string filterValue)
{
EntityQuery<Parent> query = m_ParentDomainContext.GetParentQuery();
query = query.Where(p => p.Children.Any(c => c.Name.Contains(filterValue)));
m_ParentDomainContext.Load(query, Query_Completed, null);
}
Compiles just fine, however, runtime I get "Query operator 'Any' is not supported." Exception.
Does anyone know of a good way to filter like this? Again, I'm looking for a way to set this up on the client.
EDIT: I should note, I've tried a few other queries as well, with similar results:
query = query.Where(p => p.Children.Where(c => c.Name.Contains(filterValue)).Count() != 0);
query = query.Where(p => p.Children.Where(c => c.Name.Contains(filterValue)).FirstOrDefault != null);
query = query.Where(p => p.Children.Where(c => c.Name.Contains(filterValue)).Any());
Query Operator 'Count/FirstOrDefault/Any' is not supported. I'm clearly missing something here...

As I tried to play around a little with this, I figured out that methods like First, Any and Count can't be used with LINQ to Entities (and, I believe, even NHibernate) over WCF RIA Services because they're not defined on the IQueryable itself, but, instread, are extention methods defined in the System.Linqnamespace. That is precisely why this shows as a run-time exception and not a compile-time error. The only extension methods that can be used here are those found in System.ServiceModel.DomainServices.Client (such as Where, Skip, Take, OrderBy, etc.).
This has to do with the "EntityQuery" objects, because those need to be composed and sent back to the server, whereas for the collections (such as m_ParentDomainContext.Parents in your case), you can use the System.Linq extension methods freely.
In order to implement this functionality, I suggest, as Thomas Levesque said, to expose it from the server in order to only get the data you want, or, alternatively, you can compose a query using the available constructs (the ones in System.ServiceModel.DomainServices.Client) and then apply the other filters on the resulting data (where you can use extension methods from the System.Linq namespace).
PS: I tried this with both classic Entity Framework and Entity Framework CodeFirst, and had the same results.
I hope this helps

Related

BreezeJS: Change Enum Text Values in MetadataStore

I'm absolutely loving BreezeJS and was so surprised to see that my Enum values were being displayed as their text values and not their ordinal ones! What I would love to be able to do is, on the client side, open the MetadataStore, fetch the enumeration and modify it's textual properties for display purposes.
Is this currently possible? From my research it would appear not, but I'm wondering if there is perhaps a simple workaround. Everything I've tried has involved a large number of hacks and server-side attributes, but to no avail, or the solution just seemed overly complex and not worth the benefits.
Here is what I said about how to get the enum values from raw metadata in another SO comment.
The enum values are available in the metadata generated by EF and sent to a Breeze client. I agree Breeze should pick them up automatically and put them somewhere so you don't have to make a separate request for them or extract them from the raw metadata passed to the MetadataStore.fetchMetadata success callback. It's on our backlog.
Meanwhile, you'll have to get them by hand. There is a DocCode test that shows how:
/*********************************************************
* Can can get enum types from raw EF-generated metadata
* Related to feature request #2271: Extract enum values from server metadata
*************************************************************/
asyncTest("can get enum type from raw EF-generated metadata", function() {
var serviceName = testFns.foosMetadataServiceName;
var store = new breeze.MetadataStore();
store.fetchMetadata(serviceName)
.then(metaSuccess, metaFail).fail(handleFail).fin(start);
function metaSuccess(rawMetadata) {
ok(true, "foos metadata fetched");
var enumType = rawMetadata.schema && rawMetadata.schema.enumType;
if (enumType && enumType.name ==='Color') {
var members = enumType.member;
ok(members.length,
"should have several members; members are: " + JSON.stringify(members));
} else {
ok(false, "metadata should have had one enumType, 'Color'.");
}
}
function metaFail(error) {
ok(false, "foos metadata fetch failed: " + error.message);
}
});
we're using Breeze with NHibernate and wand to do the same. Metadata generated for NHibernate are standard breeze Metadata and doesn't contain the Schema part. Any ideas how to do it?
edit: To fix our issue I added a list of all used enums in the metadata(like the structuralTypes node). Then we cache it on the client when the metadata are retrieved.
https://github.com/lnu/breeze.server.net/commit/65ad687ad13c4dd9f4a6ab6a3ed09e407e2b58ec
Thanks

Restrict ObjectSet to a related Entity and sort by a dynamic column name

Given a Parent and a valid columnName, I want to find all the related Children, ordered by a dynamic column name. Here's how I thought my code would look:
Parent. // EntityObject
Children. // EntityCollection
Where(c => c.Gender == 'm'). // IEnumerable
OrderBy(columnName, ListSortDirection.Ascending). // -- not available --
Skip(pages * pageSize).Take(pageSize);
IEnumerable.OrderBy(string columnName) doesn't exist. Looking around to accomplish the "sort by dynamic column name", I started with this excellent-looking solution: How do I create an expression tree for run time sorting? , but this operates on an IQueryable
If it did, I assume it would bring the records over the wire to sort and diminish the performance of my pager anyway. So I reordered:
Repository. // Repository
Children. // ObjectSet
Where(c => c.Parent == Parent && c.Gender == 'm'). // ObjectQuery, runtime error
OrderBy(columnName, ListSortDirection.Ascending). // IOrderedQueryable
Skip(pages * pageSize).Take(pageSize);
ObjectSet and ObjectQuery implement OrderBy(string columnName), and this code compiles, but yields the error:
Unable to create a constant value of type 'DataModel.Parent'. Only
primitive types ('such as Int32, String, and Guid') are supported in
this context.
Of course, I can get the parent ID, but the Child.ParentReference is also a non-primitive type.
I can think of a few ways that would result in loading the entire recordset across the wire, but I feel like I must be missing something, because it must not be so hard to get a set of basic directive through to the database using all MS-centric technologies.
edit: pretend I'm http://en.wikipedia.org/wiki/Quiverfull , and need to paginate my children. :)
edit2: clarified my need to query a dynamic column name.
var parents = db.Parents; // Do whatever you need to get your unsorted collection from EF here.
if (sortBy == "Gender")
{
parents = parents.OrderBy(p => p.Gender);
}
else if (sortBy == "FirstName")
{
parents = parents.OrderBy(p => p.FirstName);
}
Now, this obviously isn't sorting on multiple columns, just a single column. And you can add in more logic for sort direction as well.
Edit: took out the crap about PredicateBuilder, I was going the wrong way when I started typing this answer, and forgot to take out the old stuff.
Try replacing your OrderBy
OrderBy("age", ListSortDirection.Ascending).
with
OrderBy(x => x.Age).
also the Where
Where(c => c.Parent == Parent && c.Gender = 'm').
should read
Where(c => c.Parent == Parent && c.Gender == 'm').
So there were a couple issues I was having, both mentioned in the question title.
Sorting by a run-time-selected, or dynamic, column name required some expression building. I used #Slace's popular extension method here.
That required an IQueryable. IQueryable works for me, because every time I was accidentally transforming my query into an enumerable, I was of course bringing all the results back over the wire before paging, which I was trying to avoid. But I still needed a way to get an IQueryable for results with a relationship to an entity I already held.
It was something simple I overlooked, just joining on the Entity.Id worked, and didn't result in redundant joins at the datasource. Not quite as object-oriented as I expected from EF, but it will do.
Repository. // Repository
Children. // ObjectSet
Where(c => c.Parent.Id == Parent.Id). // ObjectQuery, works fine
OrderBy(columnName, ListSortDirection.Ascending). // IOrderedQueryable
Skip(pages * pageSize).Take(pageSize); // Only transfers 1 page

How to access NHibernate.IQueryOver<T,T> within ActiveRecord?

I use DetachedCriteria primarily, it has a static method For to construct an instance. But it seems IQueryOver is more favourable, I want to use it.
The normal way to get an instance of IQueryOver is Isession.Query, and I want get it with ActiveRecord gracefully, anyone knows the way? Thanks.
First, QueryOver.Of<T> return an instance of QueryOver<T, T>, then you build conditions with QueryOver API.
After that, query.DetachedCriteria return the equivalent DetachedCriteria, which can be used with ActiveRecord gracefully.
var query = QueryOver.Of<PaidProduct>()
.Where(paid =>
paid.Account.OrderNumber == orderNumber
&& paid.ProductDelivery.Product == product)
.OrderBy(paid=>paid.ProductDelivery.DeliveredDate).Desc;
return ActiveRecordMediator<PaidProduct>.FindAll(query.DetachedCriteria);
As far as I know, there is no direct support for QueryOver. I encourage you to create an item in the issue tracker, then fork the repository and implement it. I'd start by looking at the implementation of ActiveRecordLinqBase, it should be similar. But instead of a separate class, you could just implement this in ActiveRecordBase. Then wrap it in ActiveRecordMediator to that it can also be used in classes that don't inherit ActiveRecordBase.

Cannot retrieve user object from foreign key relationships using Linq to Entities statement

I'm trying to retrieve a user object from a foreign key reference but each time I try to do so nothing gets returned...
My table is set up like this:
FBUserID long,
UserID uniqueidentifier
so I have my repository try to get the User when it's provided the FBUserID:
public User getUserByFBuid(long uid)
{
User fbUser = null;
IEnumerable<FBuid> fbUids = _myEntitiesDB.FBuidSet.Where(user => user.FBUserID == uid);
fbUser = fbUids.FirstOrDefault().aspnet_Users;
return fbUser;
}
I've checked that the uid (FBUserID) passed in is correct, I've check that the UserID is matched up to the FBUserID. And I've also checked to make sure that fbUids.Count() > 0...
I've returned fbUids.FirstOrDefault().FBUserID and gotten the correct FBUserID, but any time I try to return the aspnet_Users or aspnet_Users.UserName, etc... I don't get anything returned. (I'm guessing it's getting an error for some reason)
I don't have debugging set up properly so that's probably why i'm having so much troubles... but so far all the checking I've done I've been doing return this.Json(/* stuff returned form the repository */) so that I can do an alert when it gets back to the javascript.
Anyone know why I would have troubles retrieving the user object from a foreign key relationship like that?
Or do you have any suggestions as to finding out what's wrong?
For now, with Entity Framework 1, you don't get automatic delayed loading, e.g. if you want to traverse from one entity to the next, you need to either do an .Include("OtherEntity") on your select to include those entities in the query, or you need to explicitly call .Load("OtherEntity") on your EntityContext to load that entity.
This was a design decision by the EF team not to support automagic deferred loading, since they considered it to be too dangerous; they wanted to make it clear and obvious to the user that he is also including / loading a second set of entities.
Due to high popular demand, the upcoming EF v4 (to be released with .NET 4.0 sometime towards the end of 2009) will support the automatic delayed loading - if you wish to use it. You need to explicitly enable it since it's off by default:
context.ContextOptions.DeferredLoadingEnabled = true;
See some articles on that new feature:
A Look at Lazy Loading in EF4
POCO Lazy Loading
Don't know if this is what you are asking but i do a join like so;
var votes = from av in dc.ArticleVotes
join v in dc.Votes on av.voteId equals v.id
where av.articleId == articleId
select v;
Did this help or am I off base?

Google Datastore problem with query on *User* type

On this question I solved the problem of querying Google Datastore to retrieve stuff by user (com.google.appengine.api.users.User) like this:
User user = userService.getCurrentUser();
String select_query = "select from " + Greeting.class.getName();
Query query = pm.newQuery(select_query);
query.setFilter("author == paramAuthor");
query.declareParameters("java.lang.String paramAuthor");
greetings = (List<Greeting>) query.execute(user);
The above works fine - but after a bit of messing around I realized this syntax in not very practical as the need to build more complicated queries arises - so I decided to manually build my filters and now I got for example something like the following (where the filter is usually passed in as a string variable but now is built inline for simplicity):
User user = userService.getCurrentUser();
String select_query = "select from " + Greeting.class.getName();
Query query = pm.newQuery(select_query);
query.setFilter("author == '"+ user.getEmail() +"'");
greetings = (List<Greeting>) query.execute();
Obviously this won't work even if this syntax with field = 'value' is supported by JDOQL and it works fine on other fields (String types and Enums). The other strange thing is that looking at the Data viewer in the app-engine dashboard the 'author' field is stored as type User but the value is 'user#gmail.com', and then again when I set it up as parameter (the case above that works fine) I am declaring the parameter as a String then passing down an instance of User (user) which gets serialized with a simple toString() (I guess).
Anyone any idea?
Using string substitution in query languages is always a bad idea. It's far too easy for a user to break out and mess with your environment, and it introduces a whole collection of encoding issues, etc.
What was wrong with your earlier parameter substitution approach? As far as I'm aware, it supports everything, and it sidesteps any parsing issues. As far as the problem with knowing how many arguments to pass goes, you can use Query.executeWithMap or Query.executeWithArray to execute a query with an unknown number of arguments.

Resources