将Linq查询结果转换为字典

426
我希望使用 Linq to SQL 向数据库添加一些行,但是在添加行之前,我想要进行“自定义检查”以确定是否必须添加、替换或忽略传入的行。
我想尽可能地降低客户端和数据库服务器之间的流量,并最小化查询次数。
为了做到这一点,我只想获取所需的最少信息进行验证,并且仅在进程开始时执行一次。
我考虑了像这样的方法,但显然它不起作用。有人有什么想法吗?
Dictionary<int, DateTime> existingItems = 
    (from ObjType ot in TableObj
        select (new KeyValuePair<int, DateTime>(ot.Key, ot.TimeStamp))
    )

最终我想要的是一个字典,而不必下载TableObject中的所有ObjectType对象。

我也考虑过以下代码,但我正在尝试找到更好的方法:

List<int> keys = (from ObjType ot in TableObj orderby ot.Key select ot.Key).ToList<int>();
List<DateTime> values = (from ObjType ot in TableObj orderby ot.Key select ot.Value).ToList<int>();
Dictionary<int, DateTime> existingItems = new Dictionary<int, DateTime>(keys.Count);
for (int i = 0; i < keys.Count; i++)
{
    existingItems.Add(keys[i], values[i]);
}
4个回答

759

尝试使用ToDictionary方法,具体操作如下:

var dict = TableObj.Select( t => new { t.Key, t.TimeStamp } )
                   .ToDictionary( t => t.Key, t => t.TimeStamp );

3
@pawan是枚举中每个元素的占位符,并且其类型与枚举对象的类型相同。 - tvanfosson
5
为什么需要.Select( t => new { t.Key, t.TimeStamp } )这个表达式? - Ben Collins
15
我认为中间的.Select导致生成的SQL仅选择Key和TimeStamp,而不是选择每一列。 - Joey Adams
5
如果您正在执行 Linq to Object 而不是 Linq to SQL,那么可以省略此中介的 Select - Pac0
1
如果有人需要的话,我是在 EF Core 5.0 的范围内寻找这个。中间的 .Select 确实避免了从数据库中选择实体模型/表中的每一列。 - Giancarlo Sierra
显示剩余2条评论

134

看了你的例子,我认为这是你想要的:

var dict = TableObj.ToDictionary(t => t.Key, t=> t.TimeStamp);

哇...也许就是这么简单...由于我对编程还比较新,我会尝试一下并进行一些分析,以确保在底层不会受到整个对象的影响。我会随时向您报告。 - Tipx
1
我刚刚完成了我的检查。不幸的是,在获取TableObj时,它会从数据库中提取所有对象,因此最终导致了流量压力。我还检查了我发布的第二种方法(并且想要避免),它们只获取必要的项目。当然,这样做需要进行2个查询,因此服务器本身必须两次搜索表,但对象映射足够简单。 - Tipx
8
你可能能够执行以下操作: TableObj.Select(t => new { t.Key, t.TimeStamp }).ToDictionary(t => t.Key, t => t.TimeStamp); LinqToSql应该能够注意到你只想获取两个特定属性(从选择中),并将它们返回。但我不确定它是否足够聪明,可以深入到ToDictionary()方法的细节中。 - Talljoe
1
不错!这是生成的查询语句:SELECT [t0].[Key], [t0].[TimeStamp] FROM [TableObj] AS [t0]。我不想抢这个功劳,所以你可以把它作为答案发布!:-P - Tipx

11

尝试以下方法

Dictionary<int, DateTime> existingItems = 
    (from ObjType ot in TableObj).ToDictionary(x => x.Key);
或者是完全利用类型推断的版本。
var existingItems = TableObj.ToDictionary(x => x.Key);

感谢您的回答,JaredPar。 我考虑过类似的方法,但我认为这将返回ObjType类型的整个对象,而我想避免下载整个对象。 - Tipx
@Tipx,您能提供一些关于您想要过滤的信息吗?添加一个过滤子句是可能的,但我无法从您的问题中确定什么是重要的。 - JaredPar
我只需要知道“新行”是否需要添加、忽略或替换另一行的时间戳,就可以了解情况。数据库中的对象有很多字段,我不需要进行验证,也不想获取整个对象的性能影响。为了保持简单,我在我的BD中有一个具有20列、100,000行的表,并希望使用前两列的值提取一个字典。 - Tipx
我刚刚检查了由那段代码生成的服务器查询,正如你可能知道的那样,它获取整个对象。 - Tipx

1
使用命名空间。
using System.Collections.Specialized;

创建 DataContext 类的实例。
LinqToSqlDataContext dc = new LinqToSqlDataContext();

使用

OrderedDictionary dict = dc.TableName.ToDictionary(d => d.key, d => d.value);

为了检索值,请使用命名空间

   using System.Collections;

ICollection keyCollections = dict.Keys;
ICOllection valueCollections = dict.Values;

String[] myKeys = new String[dict.Count];
String[] myValues = new String[dict.Count];

keyCollections.CopyTo(myKeys,0);
valueCollections.CopyTo(myValues,0);

for(int i=0; i<dict.Count; i++)
{
Console.WriteLine("Key: " + myKeys[i] + "Value: " + myValues[i]);
}
Console.ReadKey();

对于多个键值? - Kiquenet

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接