You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#调用Kusto ToEnumerable转对象列表返回默认空值问题

问题描述

执行Kusto查询获取表结构时,尝试将查询返回的响应转换为强类型对象列表,使用的Kusto查询语句如下:

tableName | getschema

该查询在Kusto Explorer中的返回结果(非完整版本)截图如下:
getschema返回结果示例

在C#代码中定义了如下DatasetColumn类用于接收查询结果:

public class DatasetColumn
{
    /// <summary>
    /// 列名
    /// </summary>
    public string? ColumnName { get; set; }

    /// <summary>
    /// 列在结构中的位置序号
    /// </summary>
    public int ColumnOrdinal { get; set; }

    /// <summary>
    /// 列存储的数据的类型
    /// </summary>
    public string? DataType { get; set; }

    /// <summary>
    /// 列存储的数据的类型
    /// </summary>
    public string? ColumnType { get; set; }
}

调用Kusto.Cloud.Data.ExtendedDataReader中提供的ToEnumerable扩展方法,从IDataReader读取结果并转为DatasetColumn对象列表,核心实现代码如下:

using (var client = storageClientFactory.CreateCslQueryProvider(new Kusto.Data.KustoConnectionStringBuilder(connectionDetails!.ClusterUrl)))
{
    var schemaQuery = KustoSchemaQueryBuilder.GetKustoSchemaQuery(connectionDetails!.EntityName);
    var clientRequestProperties = new ClientRequestProperties() { ClientRequestId = Guid.NewGuid().ToString() };
    var queryTask = client.ExecuteQueryAsync(connectionDetails.DatabaseName, schemaQuery, clientRequestProperties);
    using (var reader = await queryTask.ConfigureAwait(false))
    {
        using (reader)
        {
            return reader.ToEnumerable<DatasetColumn>().ToArray();
        }
    }
}

实际运行时,返回的列表长度和预期结果行数完全匹配,但所有对象的属性均为类型默认值:字符串属性为null,整型属性为0。
以下是可复现问题的最小可运行示例:

using Kusto.Cloud.Platform.Data;
using Kusto.Data;
using Kusto.Data.Net.Client;
using Newtonsoft.Json;

namespace ConsoleApp1
{
    class DatasetColumn
    {
        public string? ColumnName { get; set; }
        public int ColumnOrdinal { get; set; }
        public string? DataType { get; set; }
        public string? ColumnType { get; set; }
    }

    internal class Program
    {
        static void Main(string[] args)
        {
            var sb = new KustoConnectionStringBuilder("https://help.kusto.windows.net/Samples; Fed=true; Accept=true");
            using (var client = KustoClientFactory.CreateCslQueryProvider(sb))
            {
                using (var result = client.ExecuteQuery("StormEvents | getschema"))
                {
                    var cols = result.ToEnumerable<DatasetColumn>().ToArray();
                    Console.WriteLine(JsonConvert.SerializeObject(cols));
                }
            }
        }
    }
}

问题原因

这个问题的核心是ToEnumerable<T>()扩展方法的默认映射规则和常规开发预期不一致:
该方法的完整签名为public static IEnumerable<T> ToEnumerable<T>(this IDataReader reader, bool disposeReader = true, bool useProperties = false) where T : new(),其中第三个参数useProperties默认值为false,即默认仅映射目标类的公共字段,完全忽略公共属性。
你定义的DatasetColumn类中,所有成员都是get;set形式的公共属性,方法逐行生成对象时,仅会new出默认实例,不会对属性做任何赋值操作,最终就出现了列表长度和返回行数一致、但所有属性都是类型默认值的现象。
你对该扩展方法的设计用途理解没有偏差,它本身就是用来将IDataReader结果逐行转换为强类型对象序列的,只是默认映射规则和多数ORM默认映射属性的行为不同,非常容易踩坑。

修复方案

有两种简单方案可以解决这个问题,按需选择即可:

  • 方案1:调用方法时开启属性映射
    调用ToEnumerable时传入useProperties: true参数,让方法识别并映射公共属性即可,修改后的调用代码如下:
    var cols = result.ToEnumerable<DatasetColumn>(useProperties: true).ToArray();
    
    由于getschema返回的列名(ColumnName、ColumnOrdinal、DataType、ColumnType)和你定义的属性名完全一致,开启参数后不需要额外调整类定义就能得到正确赋值的对象。
  • 方案2:将类的公共属性改为公共字段
    如果不想修改方法调用逻辑,也可以调整DatasetColumn的定义,把自动属性改为公共字段,适配默认的映射规则,修改后的类如下:
    class DatasetColumn
    {
        public string? ColumnName;
        public int ColumnOrdinal;
        public string? DataType;
        public string? ColumnType;
    }
    

补充说明:该方法做映射时,列名和字段/属性名的匹配是大小写不敏感的,不需要特意修改命名适配返回结果的列名大小写。如果存在列名和属性名不一致的场景,可以给对应属性/字段添加[System.ComponentModel.DataAnnotations.Schema.Column]特性指定映射的列名。

内容的提问来源于stack exchange,提问作者Liviu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 16:48:25