Question

I have a scenario where I need to be able dynmically query for an entity, using it's related data and return from the DB, the entity AND it's related data.

enter image description here

So, for example i would write a query that looked like this to query the Contacts:

context.Contacts.Where(c.Forename == "Alex" &&
c.MetaData.Any(meta => meta.ItemName == "Email" && meta.ItemValue == "alex@myemail.com"))

However, not only do I want to return the Contact table entry, but also the Addresses for the contact and also all of the meta data for the Contact.

I've looked into the Include() statement and also the DataLoadOptions.LoadWith() options, however both of these are inefficient, in that they query on a per entity basis. So if my query matched 200 entities, there would be 200 queries for the Addresses and another 200 for the MetaData. So that is not going to be any use.

Alternatively, I could construct a .Select() statement on the Linq query that pulled together the Contact, Addresses and MetaData records. However, for a single entity with 2 addresses and 10 metadata items - that would result in 20 records being returned in a flat format. Which is horrible for a single entity - but imagine that across 200 entities that match? 4000 records to parse into 20 entities... Yuk.

So, I'm a bit stuck. If I was entirely in the DB layer, I would construct a query that dumped the Id's into a temporary table and then joined to each of the tables and returned them together and then in the domain logic I would take the IMultipleResults and construct the entities from that.

However, my problem is that I have to translate a user-driven query into linq syntax (using Expressions) and query that way. T-SQL is by no means dynamic enough to allow me to do anything like I need to.

I could query each set of data, but that would mean three hits on the database, when I only need to narrow down the result set once and pull related data for that. If the initial query to get the Contact.ContactIds takes a while I would not want to compound the user experience and make it take 3 times longer.

Any ideas on how I able to overcome this nasty combination of requirements?

Was it helpful?

Solution

I've since found this link: Using Take() in a LINQ query without Skip() causes inefficient behaviour

There seems to be a bug in using LoadWith() and Take() in a LINQ query. My testing and profiling used a Take() statement without a Skip(). Luckily in our implementation we are paging so we already use Skip() and Take() together, so we are unaffected by this bug.

Viewing the SQL executed in SqlProfiler - only one statement is executed, returning a large recordset with the data merged (as I described in my question). However, Linq seems to handle this much better and ultimately provides much more readable code, than my manual parsing.

Hope this helps.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top