请帮助理解为什么该查询返回相同的值,但是如果我使用匿名类型,它将返回正确的结果

//same values
var deviceMessageList1 = _deviceMessageRepository.Fromdevicemessages
                .Where(m => m.DeviceId == deviceId).Take(1000).ToList();
//different values
            var deviceMessageList2 = _deviceMessageRepository.Fromdevicemessages
                .Where(m => m.DeviceId == deviceId).Take(1000).Select(x=> new { Message = x.Message }).ToList();


[]

最佳答案

我做了一些假设:
  
  
  我假设您的实体类称为Fromdevicemessage
  我假设MessageString属性
  




LINQ中的.Select()不影响检索哪些项目。它仅影响检索到的项目的显示方式。
如果您了解SQL,您会发现SQL中的SELECT完全相同(这就是为什么LINQ方法在功能上有意地称为Select的原因,因为它的作用相同)

如果您了解每种方法的意图,它会有所帮助,在以下文章中将对其进行评论:

var deviceMessageList1 =_deviceMessageRepository.Fromdevicemessages

     .Where(m => m.DeviceId == deviceId)  //Only return the items which have their DevicedId set to [deviceId]
     .Take(1000)                          //Give me the first 1000 items
     .ToList()                            //Make a list from these 1000 items


请注意,您仅指定了要检索的行。您尚未指定如何格式化输出。
默认情况下,您将收到相应实体类型Fromdevicemessage的对象。

因此,您在末尾看到的列表是List<Fromdevicemessage>



var deviceMessageList1 =_deviceMessageRepository.Fromdevicemessages

     .Where(m => m.DeviceId == deviceId)       //Only return the items which have their DevicedId set to [deviceId]
     .Take(1000)                               //Give me the first 1000 items
     .Select(x => x.Message)                   //For each retrieved item, instead of the item itself, only give me its Message (= string)
     .ToList()                                 //Make a list from these 1000 strings


请注意Select语句添加的内容。它基本上告诉您不需要完整的Fromdevicemessage对象,而只需要Message属性。您基本上是在告诉编译器以下内容:


  对于当前检索到的每个Fromdevicemessage对象,将其Message属性呈现给我。


您最初使用的是Fromdevicemessage对象的集合。但是.Select()语句将该集合转换为String对象的集合。
简化的Select()方法根据您的映射(例如x => x.Message)转换源集合中的每个对象,并向您返回映射值列表。

因此,您在末尾看到的列表是List<String>



我有点作弊...

如果您没有注意到,我更改了您的Select语句。

您的版本:

.Select( x => new { Message = x.Message } )


我的版本:

.Select( x => x.Message )


两者都是有效的代码,但是它们的工作方式略有不同。


您的版本将检索到的项目转换为匿名对象。因此,结果列表将是匿名对象的列表。
我的版本将检索到的项目转换为String对象。因此,结果列表将是字符串列表。


在某些情况下,创建匿名类型很有用。最常见的是,如果要返回多个值(例如MessageRecipient属性),则很有用。

但是,您的示例仅检索单个属性。在这种情况下,使用匿名类型没有任何好处。当您要检索单个属性时使用匿名类型会使代码变得更复杂,这没有充分的理由或好处。
您要自己负责以后解包该匿名类型并读取其Message属性。

直接处理字符串而不是将其包装为匿名类型会更容易。这意味着您只需减少一层包装即可。



发表评论后更新

仔细查看您链接的图像;您的问题是为什么调试值(当您像图片中那样悬停在结果上时)为何不同?

在小弹出窗口中(扩展之前),您看到的基本上是您要检查的变量的.ToString()输出。

第一个示例由List<Fromdevicemessage>组成。由于Fromdevicemessage是您构建的自定义类(并且我假设您没有覆盖它的.ToString()方法,因此默认输出将是该类的名称,而不是其内容。

这就是它的工作原理。如果您在.ToString()类中覆盖Fromdevicemessage方法,则可以更改其外观。

public override string ToString()
{
     return $"Message : {this.Message}";
}


在第二个示例中,您正在处理匿名类型的List。匿名类型具有自定义的.ToString()方法,该方法已经向您显示了对象的内容,而不是其类名(因为匿名对象没有类名,至少在开发人员看来是这样)。

07-27 13:58