Что не так с этим DataTable при копировании SqlBulkCopy из сущности?

Я знаю, что приведенный ниже метод не предназначен для работы с какими-либо объектами, и его использование не должно быть принудительным.

Я нашел метод расширения System.Data.Linq.Table, который использует SqlBulkCopy для вставки данных. Я пытаюсь адаптировать его к Entity Framework, но он выдает странное исключение, в то время как оригинал работает для классов данных Linq-To-Sql. Я пока не смог найти брешь, это случается с любой таблицей SQL при отображении 1-1. Не могли бы вы помочь мне?

public static class ObjectQueryExtensions
{
    public static string GetName<TEntity>(
        this ObjectQuery<TEntity> objectQuery)
        where TEntity : class
    {
        var tableNameGroup = new Regex(@"FROM\s([^\s]*)\s"
            , RegexOptions.IgnoreCase);
        var sql = objectQuery.ToTraceString();
        var tableNameGroupMatch = tableNameGroup.Match(sql);
        return tableNameGroupMatch.Groups[1].Value;
    }

    public static void BulkInsert<TEntity>(
          this ObjectQuery<TEntity> objectQuery
        , IEnumerable<TEntity> items)
        where TEntity : class
    {
        using (var dt = new DataTable())
        {
            var properties = typeof(TEntity)
                .GetProperties()
                .Where(property => property.Name  != "EntityKey")
                .Where(property => property.Name  != "EntityState")
                ;
            foreach (var property in properties)
            {
                dt.Columns.Add(property.Name
                   , Nullable.GetUnderlyingType(property.PropertyType)
                   ?? property.PropertyType);
            }

            foreach (var t in items)
            {
                DataRow row = dt.NewRow();
                foreach (var info in properties)
                {
                    row[info.Name] = info.GetValue(t, null) ?? DBNull.Value;
                }
                dt.Rows.Add(row);
            }

            var entityConnection = (EntityConnection)objectQuery
                .Context.Connection;
            using (var sqlBulkCopy = new SqlBulkCopy(
                 entityConnection.StoreConnection.ConnectionString))
            {
                sqlBulkCopy.DestinationTableName = objectQuery.GetName();
                sqlBulkCopy.WriteToServer(dt);
            }
        }
    }
}

Исключение

Метод тестирования LinqExtensionsTest.ObjectQueryExtensionsTest.BulkInsertTest вызвал исключение: System.InvalidOperationException: данное значение типа Int64 из источника данных не может быть преобразовано в тип datetime указанного целевого столбца. ---> System.InvalidCastException: не удалось преобразовать значение параметра из Int64 в DateTime. ---> System.InvalidCastException: недопустимое приведение от Int64 к DateTime ..

Трассировка стека

System.Int64.System.IConvertible.ToDateTime (поставщик IFormatProvider) System.Convert.ChangeType (значение объекта, тип преобразования типа, поставщик IFormatProvider) System.Data.SqlClient.SqlParameter.CoerceValue (значение объекта, MetaType destinationTypeClient) System.Data. SqlParameter.CoerceValue (значение объекта, MetaType destinationType) System.Data.SqlClient.SqlBulkCopy.ConvertValue (значение объекта, метаданные _SqlMetaData) System.Data.SqlClient.SqlBulkCopy.ConvertValueSqlClient.SqlBulkCopy.ConvertValueSqlMetaData. WriteToServerInternal () System.Data.SqlClient.SqlBulkCopy.WriteRowSourceToServer (Int32 columnCount) System.Data.SqlClient.SqlBulkCopy.WriteToServer (таблица DataTable, DataRowState rowState) System.Data.SqlClientCopyDataSqlClientTensableDataSqlClientCopyDataSqlClientTensableDataSqlClientTensableTableDataSqlClientTensableDataSqlClientCopyles (DataRowState rowState) [TEntity] (элементы ObjectQuery1 objectQuery, IEnumerable1) в LinqExtensions \ LinqExtensions \ ObjectQueryExtensions.cs: строка 60 LinqExtensionsTest.ObjectQueryExtensionsTest. BulkInsertTest () в LinqExtensions \ LinqExtensionsTest \ ObjectQueryExtensionsTest.cs: строка 88


person Jader Dias    schedule 27.10.2009    source источник


Ответы (2)


Полученное вами исключение говорит обо всем: в вашем объекте сущности есть свойство типа Int64, которое определено как DateTime в базе данных, и нет возможности неявно преобразовать одно в другое. Вы действительно намереваетесь представить этот столбец базы данных как целое число? Возможно, это просто ошибка в определении класса сущности.

person Konamiman    schedule 27.10.2009
comment
Ваш ответ наиболее очевиден, но мне трудно в него поверить, поскольку я использовал Visual Studio Entity Designer для создания класса сущности, и у него не было бы такой ошибки. - person Jader Dias; 27.10.2009
comment
Я также перепроверил каждое поле в DataTable и Sql Profiler, и ваши подозрения не подтвердились. - person Jader Dias; 27.10.2009
comment
Это явно ошибка типа, и она исходит не от дизайнера. Но все же это ошибка типа. Этого нет в коде, который вы здесь показали, а в вашем проекте. Поэтому вам нужно посмотреть стек и найти ошибку. - person Craig Stuntz; 27.10.2009
comment
Мне пришлось бы зайти в код .NET, чтобы узнать, как обойти эту проблему. - person Jader Dias; 27.10.2009

Я знаю, что вы создали свой DataTable из своих сущностей, но я предлагаю проверить, совпадает ли порядок столбцов в DataTable с порядком столбцов в таблице (возможно, вы изменили свою базу данных и не обновили свою модель). Если это не то же самое, возможно, у вас несоответствующий тип данных и вы столкнетесь с ошибкой недопустимого приведения. Это произошло со мной ;)

person Massimiliano Sasso    schedule 17.12.2013
comment
Это правда, если вы сделаете какие-либо изменения в базе данных, которые не отражены в файле edmx, это приведет вас к этой проблеме. Если порядок столбцов в edmx не совпадает с порядком в таблице базы данных, это приведет к такому исключению. - person John Prado; 10.09.2014
comment
Решением для различного порядка столбцов в сущностях и базах данных является использование сопоставлений столбцов. - person Christian Davén; 13.12.2017