3

我已经知道我们如何使用 NHibernate 调用存储过程并填充 DTO(如此处所回答

但是,我想知道是否有可能在 NHibernate 中使用相同的 ResultTransformer 概念以某种方式填充 DataTable,或者是否有其他推荐的方法?

我更喜欢在 NHibernate 中使用 ResultTransformer 的概念。但是,我不知道它是否可能以及如何。有没有其他人试过这个?

4

2 回答 2

7

我使用此处描述的 ResultTransformer 的概念提出了以下解决方案:

  public class DataTableResultTransformer : IResultTransformer
  {
    private DataTable dataTable;

    public IList TransformList(IList collection)
    {
      var rows = collection.Cast<DataRow>().ToList();
      rows.ForEach(dataRow => dataTable.Rows.Add(dataRow));
      return new List<DataTable> { dataTable };
    }

    public object TransformTuple(object[] tuple, string[] aliases)
    {
      //Create the table schema based on aliases if its not already done
      CreateDataTable(aliases);

      //Create and Fill DataRow
      return FillDataRow(tuple, aliases);
    }

    private DataRow FillDataRow(object[] tuple, string[] aliases)
    {
      DataRow dataRow = dataTable.NewRow();
      aliases.ToList().ForEach(alias =>
                                 {
                                   dataRow[alias] = tuple[Array.FindIndex(aliases, colName => colName == alias)];
                                 });
      return dataRow;
    }

    private void CreateDataTable(IEnumerable<string> aliases)
    {
      if (dataTable == null)
      {
        dataTable = new DataTable();
        aliases.ToList().ForEach(alias => dataTable.Columns.Add(alias));
      }
    }
  }

并按如下方式使用:

    using (ISession session = sessionFactory.OpenSession())
    {
      var sqlQuery = session.CreateSQLQuery("SELECT ID, NAME, ADDRESS FROM CUSTOMER");
      var transformedQuery = sqlQuery.SetResultTransformer(new DataTableResultTransformer());
      return transformedQuery.List().Single();
    }

我刚刚创建了一个自定义 ResultTransformer,并在我的 sql 查询中使用它来根据我在 DataTableResultTransformer 中的逻辑来转换查询的结果。

为结果集中的每个项目调用 TransformTupple 方法。元组包含数据,而别名包含数据的名称。因此,我们几乎可以构建和填充 DataTable。一旦结果集中的所有项目都已由 TransformTupple 方法转换,则最后调用 TransformList 方法。集合参数包含我们在 TransformTupple 方法中转换为 DataRow 的所有项目。所以,在这里我们可以很容易地用 DataRows 填充我们的 DataTable 并返回。

希望它对其他处理相同情况的人有所帮助。

于 2013-02-27T10:28:53.040 回答
0

更新了将列数据类型考虑在内的示例

[SuppressMessage("Design", "CA1001")]
public class DataTableResultTransformer : IResultTransformer
{
    readonly Type?[] m_DataTypeOverrides = Array.Empty<Type?>();
    readonly DataTable m_DataTable = new DataTable();

    /// <summary>
    /// Initializes a new instance of the <see cref="DataTableResultTransformer"/> class.
    ///
    /// Only use this constructor if none of the columns are nullable.
    /// </summary>
    /// <remarks>Warning: If a field is NULL in the first row, that entire column will be cast as a String.</remarks>
    public DataTableResultTransformer()
    {
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="DataTableResultTransformer"/> class.
    ///
    /// 1. If dataTypeOverrides for a given column is not null, it is used.
    /// 2. If the field is not null for the first row, then that field's data type if used.
    /// 3. If both the dataTypeOverride and the field in the first row are null, the column's data type is String.
    /// </summary>
    /// <param name="dataTypeOverrides">The expected data types.</param>
    public DataTableResultTransformer(params Type?[] dataTypeOverrides)
    {
        m_DataTypeOverrides = dataTypeOverrides;
    }

    public IList TransformList(IList collection)
    {
        return new List<DataTable> { m_DataTable };
    }

    public object TransformTuple(object[] tuple, string[] aliases)
    {
        if (tuple == null || tuple.Length == 0)
            throw new ArgumentException($"{nameof(tuple)} is null or empty.", nameof(tuple));

        if (aliases == null || aliases.Length == 0)
            throw new ArgumentException($"{nameof(aliases)} is null or empty.", nameof(aliases));

        if (m_DataTable.Columns.Count == 0)
        {
            //Create the DataTable if this is the first row
            for (var i = 0; i < aliases.Length; i++)
            {
                var col = m_DataTable.Columns.Add(aliases[i]);
                if (i < m_DataTypeOverrides.Length && m_DataTypeOverrides[i] != null)
                    col.DataType = m_DataTypeOverrides[i];
                else if (tuple[i] != null && tuple[i] != DBNull.Value)
                    col.DataType = tuple[i].GetType();
            }
        }

        return m_DataTable.Rows.Add(tuple);
    }
}
于 2020-01-07T01:25:25.483 回答