Как безопасно использовать UnitOfWork DevExpress XPO в многопоточности?
Есть два БД разных структур. Нужно получить из бд данные и записать в другой тип объекта с другой структурой.
При попытки инициализации данными из БД свойства экземпляров класса через рефлексию выводится исключение что UnitOfWork
не может работать с многопоточностью.
Это исключение выводится в момент инициализации свойства типа коллекция.
Без параллельных потоков все работает, но медленно.
Думал как-то отключить сессию после получения данных из БД. Но как получил данные и в момент очистки сессии навигационные свойства типа коллекция стираю свои значения т.к. привязаны к сессии.
Есть ли вариант как-то после получения данных диспосить(освобождение ресурсов) сессию, чтобы можно было использовать навигационные свойства типа коллекция в многопоточности для инициализации типов объектов другой структур и не потерять часть загруженных данных?
Объекты инициализирую рекурсивно на основе этого кода.
PropertyInfo[] properties = type.GetProperties();
Dto result = (Dto)Activator.CreateInstance(type);
foreach (PropertyInfo property in properties) {
if (IsNestedType(typePropertyDto))
changedProperty.ChangedNestedType();
else if (IsCollection(typePropertyDto, nameProperty))
changedProperty.ChangedCollection();
else if (IsPrimitive(typePropertyDto))
property.SetValue(result, valueProperty);
}
internal void ChangedCollection()
{
Type typeDb = valueProperty.GetType().GetGenericArguments()[0];
Type typeDto = typePropertyDto.GetGenericArguments()[0];
var GenericCollection = typeof(List<>).MakeGenericType(typeDto);
IList collection = (IList)Activator.CreateInstance(GenericCollection);
var currentType = property.DeclaringType.Name;
NodeType.Node.Add(currentType);
var collectionValueProperty = (IList)valueProperty;
var countCollection = collectionValueProperty.Count;
Parallel.For(0, countCollection, i =>
{
var generateReference = typeof(XmlAssembly<,>).MakeGenericType(typeDto, typeDb);
var xmlAssembly = Activator.CreateInstance(generateReference);
MethodInfo cloneRecord = generateReference.GetMethod("CloneRecord");
var invokeCloneRecord = cloneRecord.Invoke(xmlAssembly, new object[] { collectionValueProperty[i] });
lock (_locker)
collection.Add(invokeCloneRecord);
});
NodeType.Node.Remove(currentType);
property.SetValue(result, collection);
}
Изменение:
internal void ChangedCollection()
{
Type typeDb = valueProperty.GetType().GetGenericArguments()[0];
Type typeDto = typePropertyDto.GetGenericArguments()[0];
Type GenericCollection = typeof(List<>).MakeGenericType(typeDto);
IList collection = (IList)Activator.CreateInstance(GenericCollection);
string currentType = property.DeclaringType.Name;
NodeType.Node.Add(currentType);
var collectionValueProperty = (IList)valueProperty;
var countCollection = ((IList)valueProperty).Count; //Исключение здесь
Parallel.For(0, countCollection, i =>
{
var generateReference = typeof(XmlAssembly<,>).MakeGenericType(typeDto, typeDb);
var xmlAssembly = Activator.CreateInstance(generateReference);
MethodInfo cloneRecord = generateReference.GetMethod("CloneRecord");
var invokeCloneRecord = cloneRecord.Invoke(xmlAssembly, new object[] { collectionValueProperty[i] });
lock (_locker)
collection.Add(invokeCloneRecord);
});
NodeType.Node.Remove(currentType);
property.SetValue(result, collection);
System.InvalidOperationException: "Cross-thread operation detected. 'DevExpress.Xpo.UnitOfWork(4)' is not a thread-safe object, please avoid using it simultaneously from different threads"
Исключений нет, когда коллекции не вложенные, а вот когда в экземпляре типа коллекция и обобщенный тип этой коллекции содержит в себе еще коллекцию вот в этом проблема.
public class CompanyDto
{
public string Name { get; set; }
[Key]
public decimal Id { get; set; }
public int GUIDCompany { get; set; }
public Company CompanyGuid { get; set; }
public SotrudnikDto Guid { get; set; }
public string Description { get; set; }
public List<SotrudnikDto> ListSotrudnik { get; set; }
}
public class SotrudnikDto
{
[Key]
public decimal Id { get; set; }
public string Name{ get; set; }
public SotrudnikDto SotrudnikGUID { get; set; }
public CompanyDto Guid { get; set; }
public int GUIDSotrudnik { get; set; }
public List<Order> Orders { get; set; }
}
public class OrderDto
{
[Key]
public decimal Id{ get; set; }
public string Name { get; set; }
public SotrudnikDto Sotrudnuk { get; set; }
}