views:

989

answers:

2

I'm trying to do something similar to this post where I don't pull back all columns from a particular entity, however my framework makes use of inheritence and I lose scope of the entity type after it's been cast to an anonymous type.

The structure of my Entity Framework has a base entity called Action. From here I've created two inherited entities called Event and Activity. I want to pull back the last X Actions and pass them to my strongly typed view which accepts an Action and from there determines if its an Activity or Event and renders the correct partial view.

if(Model.GetType() == typeof(Event))
{
  //render Event view
}
else if(Model.GetType() == typeof(Activity))
{
  //render Activity view
}

I can pull the last 10 as an anonymous type and then cast:

var result = from a in new DataContext().Actions
             where a.UserId == someGuidValue
             select new { a.CreatedOn, a.Summary };

List<Action> list = result.AsEnumerable()
                          .Select(o => new Action {
                                           CreatedOn = o.CreatedOn, 
                                           Summary = o.Summary
                          }).ToList();

However, once I pass the new List of Actions to my strongly typed view it loses scope of whether it's an Activity or an Event since it's been cast as an Action. My question is, without exposing the discriminator column, is there any way to cast each item to the proper type or am I going about this the wrong way?

+2  A: 

A bit kludgy, but will work:

var result = from a in new DataContext().Actions
             where a.UserId == someGuidValue
             let IsEvent = a as Event != null
             select new { a.CreatedOn, IsEvent, a.Summary };

List<Action> list = result.AsEnumerable()
                          .Select(o => o.IsEvent ?
                                           (Action) new Event {
                                               CreatedOn = o.CreatedOn, 
                                               Summary = o.Summary
                                           }
                                           : (Action) new Activity {
                                               CreatedOn = o.CreatedOn, 
                                               Summary = o.Summary
                                           }
                          }).ToList();

Example with type-specific columns, presuming that e.EventSpecific is of a nullable type.

var result = from a in new DataContext().Actions
             where a.UserId == someGuidValue
             let ev = a as Event
             let IsEvent = ev != null
             select new { a.CreatedOn, IsEvent, a.Summary, ev.EventSpecific };

List<Action> list = result.AsEnumerable()
                          .Select(o => o.IsEvent ?
                                           (Action) new Event {
                                               CreatedOn = o.CreatedOn, 
                                               Summary = o.Summary,
                                               EventSpecific = o.EventSpecific
                                           }
                                           : (Action) new Activity {
                                               CreatedOn = o.CreatedOn, 
                                               Summary = o.Summary,
                                               EventSpecific = o.EventSpecific // will be null, but using o.EventSpecific saves casting
                                           }
                          }).ToList();

If o.EventSpecific is of a non-nullable type, then you must convert it to a nullable type in the L2E query.

Craig Stuntz
Doh! That's so easy now that I look at it. I'll give it a shot when I get home.
Focus
I tried this out but it quickly became evident that I'd run into the issue of not being able to pull back Activity or Event specific columns when performing the initial pull. I was forced to create a view that pulls back the necessary columns and also pull back the discriminator column. After I pull it back I cast to the strongly typed. Not the ideal solution but it works.
Focus
You can pull back the subtype columns if you include them in the original L2E query.
Craig Stuntz
Do you mind showing me an example? I got errors if I tried to include columns that are specific to the inherited types.
Focus
Example added now.
Craig Stuntz
Works perfectly! Thanks!
Focus
A: 

You are probably on the wrong way. At first I would assume that Action should be an abstract class and you should not be able to create instances of it at all. If you then only fetch a subset of the properties and the subset does no longer allow to discriminate between events and activities, it is probably the wrong way to try making events and activities out of them.

So it actually seems not to be a technical problem - it should be quite easy to include some discrimination information in the anonymous type - but a design problem. I suggest to rethink if it is required to discriminate the query result and if so if it is really a good idea to discriminate the result in absence of an discriminator.

Daniel Brückner
Let me explain what I'm trying to achieve and then you might be able to guide me to the proper design.This is the user's feed which will display activities and events chronologically intermingled. I've created one table that holds both activities and events. I then use the inheritance to discriminate between the two types. In this manner I can simply pull back the last 10 values and have them be strongly typed. I previously had this done with stored procedures where the activities and events were both in their own table.
Focus