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に変換したすべてのアイテムが含まれています。したがって、ここでは、DataTableにDataRowsを簡単に入力して、を返すことができます。

同じ種類のシナリオを扱っている他の人に役立つことを願っています。

于 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 に答える