4

so first my entities

Entities

the problem i want to have a page with all the story titles and their types

there are three stories LongStory , CoOpStory, GenericStory

the generic story is associated with StoryType for the type of the generic story

i have two problems

first when i want to check if the story is LongStory or CoOpStory i have to get all the entity and check the entity type if it is LongStory then do something , i don't know how to retrieve some data [only the title] and check the type

my second problem like i said i want to have a page with all the story titles and their types i don't know how to do that without making a lot of queries , i can't make a join to the StoryType table because it must be GenericStory to be associated with that , so what i do first get all the stories then do an extra query for every GenericStory to get the type

3 Answers 3

4

You are looking of OfType and Concat extension methods.

To get only LongStory instances you just need to call:

var longStories = context.Stories.OfType<LongStory>().ToList();

To get your bigger query it is little bit more complex. You can either try:

var allStories = context.Stories
                        .OfType<GenericStory>()
                        .Include("StoryType") // I'm not sure how this works with concat
                        .Concat(
                             context.Stories.OfType<LongStory>.Concat(         
                                  context.Stories.OfType<CoOpStory>()));

Or you can do a projection:

var allStories = context.Stories
                        .OfType<GenericStory>()
                        .Select(s => new { s.Title, s.StoryType.Name })
                        .Concat(
                             context.Stories
                                    .OfType<LongStory>
                                    .Select(s => new { s.Title, "LongStory" })
                                    .Concat(         
                                        context.Stories
                                               .OfType<CoOpStory>()
                                               .Select(s => new { s.Title, Type })));
Sign up to request clarification or add additional context in comments.

6 Comments

lol, I just stopped writing :) Are the allStories queries are actually three roundtrips to DB? I also had Concat in mind but the parameter is IEnumerable, not IQueryable. I wasn't sure if we get three roundrips then. The context.Stories.OfType<LongStory>.Concat(context.Stories.OfType<CoOpStory>()) could possibly compressed into context.Stories.Where(s => !(s is GenericStory)).
Concat is translated to UNION ALL and Union simply to UNION. If not there is no way to do union in linq-to-entities. That compression is cool :) I thought about the way how to avoid two concatenations but this didn't come to my mind.
Good to know how Concat translates! Finally I've found something ugly (but working) for the first part of the question. I'm wondering if this really isn't possible in an easier way.
when using Concat in your first example you can't because you are Concatenating different types GenericStory with LongStory with CoOpStory
so you have to do a projection first if you want to cancat ?
|
3

Ladislav's answer is for your second question. Here is a possible solution to your first question.

As far as I can see you cannot query directly the type in an projection (using GetType() for instance won't work in LINQ to Entities). But the following will work if you want for instance only query the title and the type of a story:

var stories = context.Stories
    .Select(s => new
    {
        Title = s.Title,
        Type = (s is LongStory) ? "LongStory" :
               (s is CoOpStory) ? "CoOpStory" :
               (s is GenericStory) ? "GenericStory" :
               (s is Story) ? "Story" : // forget this if Story is abstract
               "Unknown"
    }).ToList();

You would get a list of anonymous objects where the Type property represents the type as your custom string in this query.

Not very nice because you had to change this query every time you add a new class to the hierarchy. Also the order matters (most derived classes must be first in the expression for the Type property). But I don't know another way.

1 Comment

sorry can't mark both as answer but really great info , thanks
-1

Have you tried something like this?

context.Stories.OfType<LongStory>.Where(...).Cast<Story>()
 .Union(context.Stories.OfType<GenericStory>.‌​Where(...).Include(s => s.StoryType).Cast<Story>())
 .Union(context.Stories.OfType<CoOpStory>.Where(...).Cast<Story>());

1 Comment

This looked really good and solves the problem to concat the different type collections. Unfortunately EF complains that the Include path is invalid and StoryType is not a declared property on type Story, I just tested it. It seems that the Include is applied to the DbSet<Story> before OfType<GenericStory>() actually gets applied.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.