请帮助理解为什么该查询返回相同的值,但是如果我使用匿名类型,它将返回正确的结果
//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
我假设Message
是String
属性
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
对象。因此,结果列表将是字符串列表。在某些情况下,创建匿名类型很有用。最常见的是,如果要返回多个值(例如
Message
和Recipient
属性),则很有用。但是,您的示例仅检索单个属性。在这种情况下,使用匿名类型没有任何好处。当您要检索单个属性时使用匿名类型会使代码变得更复杂,这没有充分的理由或好处。
您要自己负责以后解包该匿名类型并读取其
Message
属性。直接处理字符串而不是将其包装为匿名类型会更容易。这意味着您只需减少一层包装即可。
发表评论后更新
仔细查看您链接的图像;您的问题是为什么调试值(当您像图片中那样悬停在结果上时)为何不同?
在小弹出窗口中(扩展之前),您看到的基本上是您要检查的变量的
.ToString()
输出。第一个示例由
List<Fromdevicemessage>
组成。由于Fromdevicemessage
是您构建的自定义类(并且我假设您没有覆盖它的.ToString()
方法,因此默认输出将是该类的名称,而不是其内容。这就是它的工作原理。如果您在
.ToString()
类中覆盖Fromdevicemessage
方法,则可以更改其外观。public override string ToString()
{
return $"Message : {this.Message}";
}
在第二个示例中,您正在处理匿名类型的
List
。匿名类型具有自定义的.ToString()
方法,该方法已经向您显示了对象的内容,而不是其类名(因为匿名对象没有类名,至少在开发人员看来是这样)。