DataTable을 사용하지 않고 DataReader를 신속하게 serialize하거나 (중복 된 열 이름을 가질 수있는 DataTable을 사용하는) 가장 좋은 방법은 무엇입니까?

dapper datareader datatable

문제

IDbConnection / IDbCommand를 래핑하는 데코레이터를 사용하여 쿼리를 광범위하게 캐시합니다. 어떤 것이 'ExecuteReader ()'를 호출하면 command.text를 캐시 키 (예 : SELECT * FROM Foo )로 사용하고 이것을 관리하기 위해 (예 : new FooDbCommand("UserCacheTag") ) 태그를 데코레이터에 적용 할 수 있습니다 . Reader는 DataTable로 변환되어 일반 직렬화가 가능하며 DataTables API (CreateDataReader)를 사용하여 다시 변환됩니다.

이 모든 것이 훌륭하게 작동하지만 결함이 있습니다.

들어오는 레코드 집합에 중복 된 열 이름이 있으면 IDataReader가 DataTable로 변환 될 때 중복 된 열 이름이 숫자로 증가합니다 (예 : 'PersonID1').

IDataReader는 중복 열 이름을 허용하고 캐시 가능하며 (예 : 직렬화 가능) 원래 상태의 열 이름을 가진 IDataReader로 다시 변환 할 수 있습니다.

추가 정보:

Dapper를 주로 동적 반환 유형과 함께 사용하여 이러한 문제를 방지합니다. 멀티 맵핑을 더 많이 사용하고 싶습니다. 그러나 'Person'과 같은 유형이 한 쿼리에서 여러 번 반환되면 중복되는 열 이름이 발생합니다.

예를 들면 :

SELECT pEmployee.*, pManager.* 
FROM Persons pEmployee 
LEFT OUTER JOIN Persons pManager ON pManager.PersonID = pEmployee.ManagerPersonID

인기 답변

필자는 원래 열 이름을 'Caption'속성에 저장하는 자체 DataTable 클래스를 만들고이 스키마 테이블을 찾기 위해 GetName () 메서드를 덮어 쓰는 고유 한 IDataReader를 만들어이 작업을 수행했습니다. 상당히 간단하지만 DataTable에 단순히 'AllowDuplicateColumnNames'속성이 있으면 좋겠다.

MyDataTable

DataReader를로드하면 'Caption'속성이 원래 열 이름으로 설정됩니다. DataReader를 만들 때 스키마 이름의 'ColumnName'속성의 이름을 원래 이름 (현재 Caption 열에 저장되어 있음)으로 바꿉니다.

internal class MyDataTable : DataTable
    {
        public MyDataTable()
        {

        }

        /// <summary>
        /// This is a helper method which accounts for duplicate column names.
        /// In the loading process, it will rewrite the caption to be the original column name
        /// which can be a duplicate.
        /// </summary>
        /// <param name="dataReader"></param>
        public void LoadIDataReader(IDataReader dataReader)
        {
            var schemaTable = dataReader.GetSchemaTable();

            base.Load(dataReader);

            for (var i = 0; i < schemaTable.Rows.Count; i++)
            {
                var originalColumnName = schemaTable.Rows[i]["ColumnName"] as string;
                var currentColumnName = this.Columns[i].ColumnName;

                if(originalColumnName != currentColumnName)
                {
                    this.Columns[i].Caption = originalColumnName;
                }
            }
        }

        public IDataReader CreateIDataReader()
        {
            var dataReader = base.CreateDataReader();

            var schemaTable = dataReader.GetSchemaTable();

            for(var i = 0; i < schemaTable.Rows.Count; i++)
            {
                //this is reverse from above
                var originalColumnName = this.Columns[i].Caption;
                var currentColumnName = schemaTable.Rows[i]["ColumnName"] as string;

                if (originalColumnName != currentColumnName)
                {
                    schemaTable.Rows[i]["ColumnName"] = originalColumnName;
                }
            }

            return new MyDataReader(dataReader);
        }
    }

MyDataReader : IDataReader

이것은 데이터 배열을 받아들이고 단순히 GetName () 메서드의 데코레이터 역할을합니다.

internal class MyDataReader : IDataReader
    {
        private IDataReader _dataReader;

        public MyDataReader(IDataReader dataReader)
        {
            _dataReader = dataReader;
        }

        //other IDataReader methods not included for clarity

        public string GetName(int i)
        {
            return this.GetSchemaTable().Rows[i]["ColumnName"] as string;
        }
    }


아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow