views:

105

answers:

1

I have a table Product. Product is related to ProductDescription in a one-to-many relationship. ProductDescription can have more than one row for each product. It will have multiple rows if there are multiple translations for the description of the product. Product has a many-to-one relationship with Language. Language has a language code (en, es, etc.) as well as a LanguageId (found in ProductDescription as well).

I want to give my users the ability to request a product and further tell the application to only return descriptions in a specific language.

I am having a bear of a time accomplishing this in Linq to Entities. I want to generate SQL like this:

SELECT * FROM Product p
JOIN ProductDescription pd ON p.ProductId = pd.ProductId
JOIN (SELECT * FROM Language WHERE AlternateCode = 'es') AS l ON pd.LanguageId = l.LanguageId

(AlternateCode is the field name for the language code)

Does anyone know how to do this? What I'm left with right now is pulling down all languages, then filtering them out with Linq to Objects which is less than ideal for sure. I could get the language codes per product in a loop but that would require multiple SQL round trips which I also don't want.

appreciate any help!

A: 

Use a projection, not eager loading.

var q = from p in Context.Product
        select new ProductPresentation
        {
           Id = p.Id,
           // etc.
           Description = new ProductDescriptionPresentation
           {
               Language = (from l in p.ProductDescription.Languages
                           where l.AlternateCode.Equals("es", StringComparison.OrdinalIgnoreCase)
                           select l).FirstOrDefault(),
               // etc.
           }
        };
Craig Stuntz
This is something I have used in the past with LinqToSql but in this specific case I'm using Linq to Entities and PredicateBuilder. I suppose though that this won't be part of the predicate but instead the select statement. I may still have trouble implementing this. If I do I'll post a more complete example.
omatase
This works exactly the same in L2S and L2E. PredicateBuilder requires `AsExpandable` in L2E but otherwise works as usual.
Craig Stuntz
I'm having a difficult time figuring out where it fits. Maybe it's because I am not doing a .Select on the query which is what I think may be required for projection. Here is my query. "wherePredicate" is PredicateBuilder.var query = inventoryRepository.Products .Include("ProductDescriptions") .Include("ProductAllowedWarehouses") .Include("ProductToCategories") .Include("PriceLevels") .Include("AttachmentAssociations.Attachment").AsExpandable() .Where(wherePredicate);
omatase
That's an attempt at eager loading (which won't work), not a projection, as I suggested. Use a projection, like I said.
Craig Stuntz
Sorry, you misunderstood. I am using eager loading for some tables. If I were to do projection I know I would take the eager loading hints out for ProductDescription I just hadn't done that before I pasted in my code. I think I can fumble my way around though and find the answer. I don't want to add the Select clause because then I would have to manually map each field over to the resultset (e.g. Select (a=> new Product { ProductDescription = ...}. While allowing me to use projection it also requires I map each field from the db one at a time. I guess that is my only option here though.
omatase
So I supposed the conclusion is to use projection and just add a Select statement as in your example.I guess what I was really after was to find out if there was something simpler like this:query = inventoryRepository.Products .Include("ProductDescriptions.Languages").Where<Language>(a => a.AlternateCode.Equals("es", StringComparison.OrdinalIgnoreCase).Include("ProductAllowedWarehouses") .Include("ProductToCategories") .Include("PriceLevels") .Include("AttachmentAssociations.Attachment").AsExpandable() .Where(wherePredicate);something so I could still count on automatic mapping.
omatase