实体框架 - 选择特定列并返回强类型而不会丢失强制转换

时间:2009-10-29 20:15:45

标签: asp.net-mvc linq linq-to-sql entity-framework inheritance

我正在尝试执行与this post类似的操作,我不会从特定实体中撤回所有列,但是我的框架使用了继承,并且在实体类型转换后我失去了实体类型的范围匿名类型。

我的Entity Framework的结构有一个名为 Action 的基本实体。从这里开始,我创建了两个名为 Event Activity 的继承实体。我想撤回最后的X个动作并将它们传递给我的强类型视图,该视图接受一个Action,并从那里确定它是一个Activity还是Event并呈现正确的局部视图。

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

我可以将最后10个作为匿名类型拉出然后投射:

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();

但是,一旦我将新的动作列表传递给我的强类型视图,它就会失去一个活动或事件的范围,因为它被强制转换为动作。我的问题是,在不暴露鉴别器列的情况下,是否有任何方法可以将每个项目转换为正确的类型,或者我是否以错误的方式进行此操作?

2 个答案:

答案 0 :(得分:5)

有点kludgy,但会起作用:

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();

特定于类型的列的示例,假设e.EventSpecific属于可空类型。

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();

如果o.EventSpecific属于非可空类型,则必须在L2E查询中将其转换为可空类型。

答案 1 :(得分:0)

你可能走错了路。首先,我假设Action应该是一个抽象类,你根本不应该创建它的实例。如果您只获取属性的子集并且子集不再允许区分事件和活动,那么尝试从它们中创建事件和活动可能是错误的方法。

所以它实际上似乎不是一个技术问题 - 在匿名类型中包含一些歧视信息应该很容易 - 但这是一个设计问题。我建议重新考虑是否需要区分查询结果,如果是,如果在没有鉴别器的情况下区分结果真的是个好主意。