Я пытаюсь использовать Fluent NHibernate для переноса базы данных, для которой требуется массажирование базы данных. Исходная база данных - это база данных MS Access, и текущая таблица, на которую я застрял, - это поле с полем OLE Object. Целевая база данных - это база данных MS SQL Server Express.
В объекте я просто имел это поле, определенное как byte[]
, однако при загрузке, даже если просто загружать это одиночное поле для одной записи, я попадал в System.OutOfMemoryException
byte[] test = aSession.Query<Entities.Access.Revision>().Where(x => x.Id == 5590).Select(x => x.FileData).SingleOrDefault<byte[]>();
Затем я попытался реализовать тип blob, указанный здесь, но теперь при запуске я получаю сообщение об ошибке:
"Невозможно передать объект типа 'System.Byte []' для ввода типа 'TestProg.DatabaseConverter.Entities.Blob'." }
Я не могу себе представить, что Ole Object больше 100 МБ, но не смог проверить. Есть ли хороший способ использования Fluent NHibernate для копирования этого из одной базы данных и сохранения его в другой или мне нужно посмотреть другие параметры?
Мой обычный цикл для обработки:
IList<Entities.Access.Revision> result;
IList<int> recordIds = aSession.Query<Entities.Access.Revision>().Select(x => x.Id).ToList<int>();
foreach (int recordId in recordIds)
{
result = aSession.Query<Entities.Access.Revision>().Where(x => x.Id == recordId).ToList<Entities.Access.Revision>();
Save(sqlDb, result);
}
Функция сохранения просто копирует свойства из одного в другой и для некоторых объектов используется для управления данными или предоставления обратной связи пользователю, связанному с проблемами данных. Я использую сеансы без состояния для обеих баз данных.
-
От дальнейшего тестирования объекты, которые, по-видимому, висят, составляют около 60-70 мб. В настоящее время я тестирую захват данных с помощью OleDbDataReader с помощью GetBytes.
-
Обновление (24 ноября): Мне еще предстоит найти способ заставить это работать с NHibernate. Я получил эту работу с регулярными объектами команды db. Я поставил код для функции, которую я сделал ниже, для кого-то любопытного, кто это нашел. Это код из моего конвертера базы данных, поэтому объекты с префиксом 'a' являются объектами базы данных доступа и 's' являются sql-тегами.
public void MigrateBinaryField(int id, string tableName, string fieldName)
{
var aCmd = new OleDbCommand(String.Format(@"SELECT ID, {0} FROM {1} WHERE ID = {2}", fieldName, tableName, id), aConn);
using (var reader = aCmd.ExecuteReader(System.Data.CommandBehavior.SequentialAccess))
{
while (reader.Read())
{
if (reader[fieldName] == DBNull.Value)
return;
long read = 0;
long offset = 0;
// Can't .WRITE a NULL column so need to set an initial value
var sCmd = new SqlCommand(string.Format(@"UPDATE {0} SET {1} = @data WHERE OldId = @OldId", tableName, fieldName), sConn);
sCmd.Parameters.AddWithValue("@data", new byte[0]);
sCmd.Parameters.AddWithValue("@OldId", id);
sCmd.ExecuteNonQuery();
// Incrementally store binary field to avoid OutOfMemoryException from having entire field loaded in memory
sCmd = new SqlCommand(string.Format(@"UPDATE {0} SET {1}.WRITE(@data, @offset, @len) WHERE OldId = @OldId", tableName, fieldName), sConn);
while ((read = reader.GetBytes(reader.GetOrdinal(fieldName), offset, buffer, 0, buffer.Length)) > 0)
{
sCmd.Parameters.Clear();
sCmd.Parameters.AddWithValue("@data", buffer);
sCmd.Parameters.AddWithValue("@offset", offset);
sCmd.Parameters.AddWithValue("@len", read);
sCmd.Parameters.AddWithValue("@OldId", id);
sCmd.ExecuteNonQuery();
offset += read;
}
}
}
}