C#/WPF中使用DbContext.ExecuteStoreQuery返回自定义元组的问题
解决ExecuteStoreQuery返回自定义类型或Tuple的问题
这个问题我之前也碰到过,咱们一步步拆解原因,再给出可行的解决方案:
一、为什么自定义类的结果为空?
你当前的SqlTwoStringsClass用的是公共字段,但EF的ExecuteStoreQuery默认只会映射目标类型的公共属性(带get; set;的那种),而且要求属性名称和查询返回的列名完全匹配(大小写不敏感,但最好一致)。你的字段text1、text2既不是属性,名称也和查询里的str1、str2不对应,所以EF没法把查询结果赋值进去,自然就是空的。
二、为什么Tuple会抛出初始化异常?
Tuple<string, string>是不可变类型:它没有无参构造函数,而且Item1、Item2是只读属性。EF需要通过反射创建对象实例并设置属性值,但Tuple的设计不允许这样操作,所以会抛出初始化异常。Tuple不适合作为EF查询的直接返回类型。
三、正确的实现方式
方案1:修复自定义DTO类(推荐)
创建一个标准的DTO类,用公共属性,确保属性名和查询列名对应(或者用SQL别名适配):
namespace MyApp { // 推荐设为public,方便跨程序集使用,同一程序集internal也可以 public class SqlTwoStringsDto { // 属性名和查询的列名一致,EF会自动映射 public string str1 { get; set; } public string str2 { get; set; } } }
然后查询代码保持不变,只需要替换类型:
string sql_Select_From_MY_TABLE = "SELECT DISTINCT [str1], [str2] FROM [GP].[dbo].[MY_TABLE] WHERE ID = {0} AND ID2 IS NOT NULL"; ObjectResult<SqlTwoStringsDto> sqlResult = myDbContext.ExecuteStoreQuery<SqlTwoStringsDto>(sql_Select_From_MY_TABLE, someID); foreach (SqlTwoStringsDto item in sqlResult) { Utils.printToConsole(item.str1 + ", " + item.str2); }
如果不想修改类的属性名,也可以在SQL里给列加别名,适配类的属性:
SELECT DISTINCT [str1] AS text1, [str2] AS text2 FROM [GP].[dbo].[MY_TABLE] WHERE ID = {0} AND ID2 IS NOT NULL
对应的DTO类:
public class SqlTwoStringsDto { public string text1 { get; set; } public string text2 { get; set; } }
方案2:手动映射到Tuple(不推荐,适合临时场景)
如果一定要用Tuple,可以手动读取查询结果并创建Tuple:
string sql_Select_From_MY_TABLE = "SELECT DISTINCT [str1], [str2] FROM [GP].[dbo].[MY_TABLE] WHERE ID = {0} AND ID2 IS NOT NULL"; var reader = myDbContext.ExecuteStoreQuery<System.Data.Common.DbDataRecord>(sql_Select_From_MY_TABLE, someID).GetEnumerator(); while (reader.MoveNext()) { var resultTuple = Tuple.Create( (string)reader.Current["str1"], (string)reader.Current["str2"] ); Utils.printToConsole(resultTuple.Item1 + ", " + resultTuple.Item2); }
或者用DbContext的Database.SqlQuery结合LINQ映射:
var sql = "SELECT DISTINCT [str1], [str2] FROM [GP].[dbo].[MY_TABLE] WHERE ID = @p0 AND ID2 IS NOT NULL"; var tupleList = myDbContext.Database.SqlQuery<object[]>(sql, someID) .Select(row => Tuple.Create((string)row[0], (string)row[1])) .ToList(); foreach (var tuple in tupleList) { Utils.printToConsole(tuple.Item1 + ", " + tuple.Item2); }
总结
对于这类自定义查询结果,使用专门的DTO类是最佳实践——代码更清晰、易维护,EF也能自动完成映射,避免手动处理数据的繁琐。
内容的提问来源于stack exchange,提问作者Vlad
相关产品推荐
相关产品推荐

