如何在执行LINQ查询之前获取LINQ查询结果的类型?

时间:2014-03-11 08:45:12

标签: c# linq entity-framework

EntityFramework执行LINQ查询时,如果查询将某些东西作为动态类返回,则无法获得实际类型的结果。

我有一个抽象类:

abstract class Person
{
    public string Name { get; set; }
    //and about 1000 other properties
}

和2个派生类:

class RealPerson : Person
{
    public void Print()
    {
        Console.WriteLine("Type=RealPerson, Name=" + Name);
    }
}
class LegalPerson : Person
{
    public void Print()
    {
        Console.WriteLine("Type=LegalPerson, Name=" + Name);
    }
}

我的LINQ TO SQL查询:

var lst = 
    EFContext.Persons.Select(item=> new { DynamicClass_Name = item.Name }).ToList();

现在,对于lst中的每个项目,我需要知道其类的类型以将此项目转换为该类型,但item.GetType()返回动态类型。 例如,假设lst的一个项目是RealPerson(称为dynamicTypeItem),所以如果我知道它的类型是RealPerson,我将使用以下代码将此dynamicTypeItem强制转换为RealPerson

var value = dynamicTypeItem.GetType().GetProperty("DynamicClass_Name").GetValue(dynamicTypeItem);
var result = (RealPerson)Activator.CreateInstance(typeof(RealPerson));
result.GetType().GetProperty("Name").SetValue(result, value);

但是我不知道这个dynamicTypeItem的类型(它有一个动态类型); 如何实现lst的每个项目的类型? 上面的查询只选择实体的1个属性(Name属性)是非常重要的,所以我不能使用这个代码:

var lst = 
    EFContext.Persons.ToList().Select(item=> new { DynamicClass_Name = item.Name, Type=item.GetType() });

所以在将此项目转换为动态类型之前,我需要知道lst的每个项目的类型。

EDIT1 更多解释:结果不能是Person,因为Person是抽象的。结果为RealPersonLegalPerson,当我在转换期间仅选择RealPersonLegalPerson中的一个属性时,强类型为匿名类型时,将错过原始实体的类型。

2 个答案:

答案 0 :(得分:2)

您想从数据库表的一个属性的值中引出类型吗?无法从中选择类型,因为未从数据库中提取类型信息。

如果你解释它真正需要什么,我们仍然可以帮助你,但这个约束:

  

上述查询仅选择实体

的1个属性(Name属性)非常重要

使你想要实现的目标变得不可能。您必须从数据库中选择更多内容。

我如何成像这样做,虽然如果可能的话我会首先看看数据库设计:

public partial class Person {
  public Person() { 
    _dotnetType = this.GetType().Fullname; 
    _dotnetAssembly = this.GetType().Assembly.Fullname; 
  }
  private string _dotnetType;
  private string _dotnetAssembly;
  public string DotNetType { get { return _dotnetType; } set { _dotnetType = value } }
  public string DotNetAssembly { get { return _dotnetAssembl; } set { _dotnetAssembly = value } }
}

// Example usage
var peeps = from person in Entities.Persons
            select new { Name = person.Name, Type = DotNetType, Assembly = DotNetAssembly };

var loadedPeople = peeps.ToList() // enumerate it
                   .Select( p => {
                     var instance = Activator.CreateInstance(p.Assembly, p.Type);
                     var property = p.GetType().GetProperties().First(prop => prop.Name == "Name");
                     property.SetValue(instance, p.Name, null);
                   });

我没有尝试过这段代码,但它应该可以工作,只需确保调用Person中的无参数构造函数。关键是数据库将“丢失”类型信息,因此最好将其存储为字符串。请记住,您还需要将列添加到数据库并映射它们!

答案 1 :(得分:1)

这看起来像是一个XY问题。您的问题是,如何使用实体框架(AND NOT Linq To SQL)从表中实现对象,我有一个鉴别器?

答案很简单。

你不要!

对您的Entity Framework模型使用Single Table inheritance,您的LinqToEntities查询非常简单。

一旦你有了这个,那绝对没有理由为你的投射做什么。

您应该考虑对象而不是ORM表。

因此,您可以执行以下操作以获取所有LegalPersons的名称' Alice'

var legallyAlices = EFContext.Persons.OfType<LegalPerson>()
                            .Where(x => x.Name == 'Alice');

OR

var legallyAlices = from legalPerson in EFContext.Persons.OfType<LegalPerson>()
                    where legalPerson.Name == 'Alice'
                    select legalPerson;