如何通过context.ExecuteQuery将SQL Server动态Pivot数据传入Visual Studio
解决SQL Server动态Pivot存储过程在C#中处理动态列的问题
你遇到的核心问题是LINQ to SQL的ExecuteQuery<dynamic>返回的动态对象无法通过TypeDescriptor.GetProperties获取属性——它返回的不是真正的ExpandoObject,而是LINQ to SQL内部封装的动态类型,直接导致你的内层循环根本执行不了。下面给你两个可行的解决方案:
方案1:改用DataTable接收动态结果(推荐)
DataTable天生支持动态列结构,能完美适配存储过程返回的不固定列,之后再把DataTable转换成你需要的List<Dictionary<string, object>>:
public List<Dictionary<string, object>> Neg_conceptos_nomina_pivote(string Vaux_cia, DateTime Vaux_Fecini, DateTime Vaux_fecfin, string VauxCcostos, bool Vaux_abierta_cerrada, bool Vaux_checkDeducciones) { List<Dictionary<string, object>> resultado = new List<Dictionary<string, object>>(); // 直接用SqlConnection操作,避开LINQ to SQL的动态类型限制 using (Dat_GrupoFaroDBDataContext contexto_grupofaro = new Dat_GrupoFaroDBDataContext()) using (SqlConnection conn = new SqlConnection(contexto_grupofaro.Connection.ConnectionString)) { conn.Open(); using (SqlCommand cmd = new SqlCommand("uspconceptos_nomina_pivote", conn)) { cmd.CommandType = CommandType.StoredProcedure; // 必须用参数化查询,彻底避免SQL注入风险! cmd.Parameters.AddWithValue("@Vaux_cia", Vaux_cia); cmd.Parameters.AddWithValue("@Vaux_Fecini", Vaux_Fecini); cmd.Parameters.AddWithValue("@Vaux_fecfin", Vaux_fecfin); cmd.Parameters.AddWithValue("@Vaux_abierta_cerrada", Vaux_abierta_cerrada); cmd.Parameters.AddWithValue("@Vaux_checkDeducciones", Vaux_checkDeducciones); using (SqlDataReader reader = cmd.ExecuteReader()) { DataTable dt = new DataTable(); dt.Load(reader); // 将DataTable逐行转换为字典 foreach (DataRow row in dt.Rows) { Dictionary<string, object> rowDict = new Dictionary<string, object>(); foreach (DataColumn col in dt.Columns) { rowDict.Add(col.ColumnName, row[col] ?? DBNull.Value); } resultado.Add(rowDict); } } } } return resultado; }
方案2:修复原ExpandoObject的处理逻辑
如果你坚持要用LINQ to SQL的方式,可以通过反射读取动态对象的属性,替代TypeDescriptor.GetProperties:
public List<Dictionary<string, object>> Neg_conceptos_nomina_pivote(string Vaux_cia, DateTime Vaux_Fecini, DateTime Vaux_fecfin, string VauxCcostos, bool Vaux_abierta_cerrada, bool Vaux_checkDeducciones) { List<Dictionary<string, object>> resultado = new List<Dictionary<string, object>>(); using (Dat_GrupoFaroDBDataContext contexto_grupofaro = new Dat_GrupoFaroDBDataContext()) { // 先改成参数化查询,杜绝SQL注入! var resul = contexto_grupofaro.ExecuteQuery<dynamic>( "uspconceptos_nomina_pivote @0, @1, @2, @3, @4", Vaux_cia, Vaux_Fecini, Vaux_fecfin, Vaux_abierta_cerrada, Vaux_checkDeducciones); foreach (var item in resul) { IDictionary<string, object> resultadoitem = new ExpandoObject(); // 用反射获取动态对象的公开属性 var properties = item.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public); foreach (var prop in properties) { var value = prop.GetValue(item); resultadoitem.Add(prop.Name, value); } resultado.Add(new Dictionary<string, object>(resultadoitem)); } return resultado; } }
关键提醒:SQL注入风险
你原来的代码直接拼接SQL字符串,存在非常严重的SQL注入漏洞!上面两个方案都改用了参数化查询,一定要坚持这种写法,绝对不要把用户输入直接拼进SQL语句里。
内容的提问来源于stack exchange,提问作者fernando munera
相关产品推荐
相关产品推荐

