【问题标题】:How can I get the type of the results of a LINQ query before executing it?如何在执行之前获取 LINQ 查询的结果类型?
【发布时间】:2014-03-11 08:45:11
【问题描述】:

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 个属性(名称属性)非常重要,因此我不能使用此代码:

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

所以我需要知道 lst 的每个项目的类型,然后再将这个项目转换为动态类型。

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

【问题讨论】:

  • 动态类型是什么意思?动态类型 == dynamic关键字?
  • 你好,其实它还是强类型,你在查询中使用匿名类型,如果你使用Visual Studio,你只需要在选择上,那么它应该你的结果类型。
  • @findeberg 正如 Panada Zhang 提到的,在这个问题中动态类型的平均值是匿名类型。此表达式在编译时创建一个名为“匿名”的新类型:item=> new { DynamicClass_Name = item.Name }
  • 这个匿名类型只有一个属性(DynamicClass_Name)
  • 您使用的是 Linq to SQL 还是实体框架?为什么你甚至需要演员,你有一个适合所有人的二传手。为什么@#$% 你投射你的查询?您似乎完全错过了 ORM 的要点。

标签: c# linq entity-framework


【解决方案1】:

您想从数据库表的一个属性的值中获取类型?无法从中选择类型,因为类型信息不是从数据库中获取的。

如果您解释了您真正需要的是什么,我们可能仍然可以帮助您,但是这个限制:

以上查询仅选择实体的 1 个属性(名称属性)非常重要

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

我如何想象这样做,尽管如果可能的话,我会先看看数据库设计:

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 中的无参数构造函数被调用。关键是数据库会“丢失”类型信息,因此最好将其存储为字符串。请记住,您还需要将列添加到数据库并映射它们!

【讨论】:

  • 不,我根本不想从数据库表的 一个属性 的值中得出类型!我需要知道结果是RealPersonLegalPerson 类型。
  • 结果不能是Person,因为它是抽象的。结果是RealPersonLegalPerson。并且当我在将强类型转换为匿名类型期间仅选择RealPerson|LegalPerson 的属性之一时,原始实体的类型会丢失。
  • @Merta 您无法从名称属性中知道!一串!一个字符串就是您从数据库中选择的所有内容,该字符串如何告诉您它属于什么?
  • 我需要这样的东西:EFContext.Persons.Select(item=> new { DynamicClass_Name = item.Name, OriginalType=??? }).ToList()
  • 遗憾的是,类型信息没有存储在数据库中,它存储为映射,因此它知道如何将完整实体(即行)转换为相应的模型类型。你所要求的并不是那么容易做到的。最简单的方法是创建一个新列,例如“DOTNET_TYPE”,它是 varchar2 或字符串,然后使用激活器来实例化该特定类型的实例。
【解决方案2】:

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

答案很简单。

你没有!

为您的实体框架模型使用Single Table inheritance,您的 LinqToEntities 查询将非常简单。

一旦你有了这个,你的投影绝对没有理由。

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

因此,您可以执行以下操作来获取所有名为“Alice”的 LegalPersons

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

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

【讨论】:

  • 我使用 EF(不是 LINQ To SQL),在 ORM 中,我的模型就像给定链接的模型(单表继承)。您的解决方案是一种选择所有LegalPersons 或对特定表进行查询的方法,但我的查询可以加入我数据库的所有表!所以我无法通过模型校正来处理这个问题。我需要自定义所有表的投影的可能性,无论该模型是否映射到抽象类。
  • 不清楚你在问什么。也许您应该描述您的领域问题,而不是直接深入到反射和匿名类型。
  • @flindeberg 得到了确切的问题,也许在他的回答下阅读 cmets 清楚的问题并帮助我们。
  • 也许有点澄清。看起来您正在尝试使用 Entity Framework 进行一些复杂的操作(实际上您似乎想绕过其中的大部分内容)。您的 cmets 注意到您正在尝试提高性能,但您发现上述“解决方案”实际上要慢得多。反思往往是。我试图引导你远离这些事情,因为与架构良好的系统相比,你显然会得到更大的内存占用和更慢的性能。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-09-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多