public void GetGuidByObjectСравнениеGuid() { var obj = PKHelper.CreateDataObject <DataObjectForTest>(g1); Assert.True( PKHelper.EQPK(g1, PKHelper.GetGuidByObject(obj)), "Возвращенный Guid не равен исходному."); }
public static void GetObjForDate(DateTime date, ref DataObject obj, Guid?changeAuditPK = null, bool onlySelfObj = true) { if (obj != null) { try { //Загружаем текущее состояние объекта по выбранному представлению obj.DisableInitDataCopy(); //это объект никогда не будет сохраняться в бд, копия данных -, производительность + DataService.LoadObject("AuditView", obj, true, false); } catch (Exception ex) { //throw new LoadChangedObjectException(appObjType.Name, appObjPK, ex.Message); LogService.LogError("Ошибка при вычитке объекта из бд"); //TODO поймать исключение о существовании объекта //объект в текущий момент может быть удалён, тогда его нельзя будет загрузить из бд // нужно ли вообще по нему что-то высылать кроме ключа елси его он всё равно будет удалён следующими сообщениями? //Объект восстановиться, если ведется аудит удаления для него - запись удаленя - это занулление всех текущих значений } var changedAuditEntity = new List <AuditEntity>(); try { var lcs = LoadingCustomizationStruct.GetSimpleStruct(typeof(AuditEntity), AuditEntity.Views.AuditEntityE); lcs.LimitFunction = FunctionBuilder.BuildAnd( FunctionBuilder.BuildEquals(nameof(AuditEntity.ObjectPrimaryKey), obj.__PrimaryKey), FunctionBuilder.BuildGreaterOrEqual <AuditEntity>(x => x.OperationTime, date)); lcs.ColumnsSort = new[] { new ColumnsSortDef(nameof(AuditEntity.OperationTime), SortOrder.Desc) }; changedAuditEntity = DataService.LoadObjects(lcs).Cast <AuditEntity>().ToList(); } catch (Exception ex) { LogService.LogError(@"Ошибка при загрузке операций изменения из аудита"); } var lastChange = changedAuditEntity.LastOrDefault(); if (changeAuditPK.HasValue && PKHelper.GetGuidByObject(lastChange) != changeAuditPK) { LogService.LogError( @"Ошибка сбой при загрузке изменеий! Обнаружено не соответствиие загруженных изменений и ссылки на изменения аудита в synclogitem"); } var objType = obj.GetType(); var auditFieldsLcs = LoadingCustomizationStruct.GetSimpleStruct(typeof(AuditField), ViewForField); foreach (var changeEntity in changedAuditEntity) { if (changeEntity.OperationType != operationCreateType) { var changedFields = new List <AuditField>(); try { auditFieldsLcs.LimitFunction = FunctionBuilder.BuildEquals <AuditField>(x => x.AuditEntity, changeEntity); changedFields = DataService.LoadObjects(auditFieldsLcs).Cast <AuditField>().ToList(); } catch (Exception ex) { LogService.LogError( $@"Произошла ошибка при попытке получить набор изменения изменения полей за период.{ Environment.NewLine }{ex.Message}"); } //Берём только изменения, вспомогательные объекты LinkedPrimaryKey остаются в основном списке var onlySelfChangedFields = changedFields.Where(y => y.MainChange == null); foreach (var changedField in onlySelfChangedFields) { var mainChange = changedFields.FirstOrDefault(x => PKHelper.EQPK(x.MainChange, changedField)); if (mainChange == null) { //Если основного изменения нет, то это обычное поле var propertyInfo = objType.GetProperty(changedField.Field); if (propertyInfo != null) { var typeprop = propertyInfo.PropertyType; object value = null; try { if (changedField.OldValue != null) { value = Convert.ChangeType(changedField.OldValue, typeprop); } propertyInfo.SetValue(obj, value); } catch (Exception ex) { LogService.LogError(value != null ? $"Ошибка установки поля {changedField.Field}" : $"Ошибка преобразования типа полей"); } } else { LogService.LogError( $@"Ошбика не найдено поле {changedField.Field} в объекте {objType.Name}."); } } else { // В аудите детейл отличается от мастера тем, что у него приписывается в скобках позиция if (Regex.IsMatch(changedField.Field, "[ ][(][0-9]+[)]$")) { var separateIndex = changedField.Field.IndexOf(" ", StringComparison.Ordinal); var detailNameFromField = changedField.Field.Substring(0, separateIndex); var propertyInfo = objType.GetProperty(detailNameFromField); if (propertyInfo != null) { var detailValue = propertyInfo.GetValue(obj) as DetailArray; if (detailValue != null) { //TODO исследовать возможность пустой ссылки на детейл if (changedField.OldValue == "-NULL-") { var key = new KeyGuid(mainChange.NewValue); detailValue.RemoveByKey(key); } else { var detailItemType = detailValue.ItemType; var oldDetailObj = GetInstanseOfObjWithPK(detailItemType, mainChange.OldValue); detailValue.AddObject(oldDetailObj); } } /*else * { * LogService.LogError( * $@"Ошибка не найден детейл {detailNameFromField} в объекте {objType.Name}."); * }*/ } else { LogService.LogError( $@"Ошибка не найден детейл { detailNameFromField } в объекте {objType.Name}."); } } else { var propertyInfo = objType.GetProperty(changedField.Field); if (propertyInfo != null) { // Это изменение мастера. if (changedField.OldValue == "-NULL-") { propertyInfo.SetValue(obj, null); } else { var typeprop = propertyInfo.PropertyType; var oldMasterObj = GetInstanseOfObjWithPK(typeprop, mainChange.OldValue); propertyInfo.SetValue(obj, oldMasterObj); } } else { LogService.LogError( $@"Ошбика не найден мастер {changedField.Field} в объекте {objType.Name}."); } } } } } else { // Если откатываем создание объекта, то возвращаем нулл. obj = null; } } // На этом этапе основной объект и все его собственные поля и зависимые сущности возвращены на дату // Получаем мастера и откатываем их поля, рекурсивно вызывая этот метод // Получаем детейлы объекта и откатываем их поля, рекурсивно вызывая этот метод if (!onlySelfObj) { var objProperties = objType.GetProperties(); foreach (var property in objProperties) { var typeprop = property.PropertyType; if (typeprop.IsSubclassOf(typeof(DataObject))) { //Перебираем все мастера var masterValue = property.GetValue(obj) as DataObject; GetObjForDate(date, ref masterValue, null, onlySelfObj); } else if (typeprop.IsSubclassOf(typeof(DetailArray))) { //Перебираем все детейлы var detailValue = property.GetValue(obj) as DetailArray; var detailObjects = detailValue.GetAllObjects(); foreach (var dataObject in detailObjects) { var currentObj = dataObject; GetObjForDate(date, ref currentObj, null, onlySelfObj); } } } } } }
private static AuditChange GetChangesByPeriodByPK(DateTime from, DateTime until, string objPk, bool firstLoop, bool recursive) { var операцииЗаПериод = new List <AuditEntity>(); try { var lcs = LoadingCustomizationStruct.GetSimpleStruct(typeof(AuditEntity), AuditEntity.Views.AuditEntityE); lcs.LimitFunction = FunctionBuilder.BuildAnd( FunctionBuilder.BuildEquals(nameof(AuditEntity.ObjectPrimaryKey), objPk), FunctionBuilder.BuildBetween <AuditEntity>(x => x.OperationTime, from, until)); операцииЗаПериод = DataService.LoadObjects(lcs).Cast <AuditEntity>().OrderBy(x => x.OperationTime) .ToList(); } catch (Exception ex) { LogService.LogError( $@"Произошла ошибка при попытке получить изменения за период {from.ToShortDateString()} - { until.ToShortDateString() } для объекта с ключом {objPk}.{Environment.NewLine}{ex.Message}"); } var итоговыйСтатусОбъекта = GetAuditOperationType(операцииЗаПериод); var изменениеОбъекта = new AuditChange { Type = GetObjTypeByPK(objPk), ObjPrimaryKey = objPk, Operation = итоговыйСтатусОбъекта }; if (итоговыйСтатусОбъекта != tAuditOperation.CreateAndDelete && итоговыйСтатусОбъекта != tAuditOperation.NoChange && (firstLoop || recursive)) { var fieldsLcs = LoadingCustomizationStruct.GetSimpleStruct(typeof(AuditField), ViewForField); foreach (var операцияИзменения in операцииЗаПериод) { var измененияПолей = new List <AuditField>(); try { fieldsLcs.LimitFunction = FunctionBuilder.BuildEquals <AuditField>(x => x.AuditEntity, операцияИзменения); измененияПолей = DataService.LoadObjects(fieldsLcs).Cast <AuditField>().ToList(); } catch (Exception ex) { LogService.LogError( $@"Произошла ошибка при попытке получить набор изменения изменения полей за период { from.ToShortDateString() } - {until.ToShortDateString()} для объекта с ключом {objPk} для изменения с ключом { операцияИзменения.__PrimaryKey }.{Environment.NewLine}{ex.Message}"); } var толькоСобственныеИзменения = измененияПолей.Where( y => y.MainChange != null || !измененияПолей.Exists(x => PKHelper.EQPK(x.MainChange, y))); foreach (var измененныйАтрибут in толькоСобственныеИзменения) { if (измененныйАтрибут.MainChange == null) { // Это изменение собственного поля. изменениеОбъекта.FieldsChanges[измененныйАтрибут.Field] = измененныйАтрибут.NewValue; } else { var главноеИзменение = измененияПолей.First(x => PKHelper.EQPK(x, измененныйАтрибут.MainChange)); if (Regex.IsMatch(главноеИзменение.Field, "[ ][(][0-9]+[)]$")) { // Это изменение детейла. var номерДетейла = Regex.Match(главноеИзменение.Field, "[ ][(][0-9]+[)]$").Value; // Если ссылка на детейл стала нулл, то соберём изменение удаления этого объекта. var ключДетейла = измененныйАтрибут.NewValue == "-NULL-" ? измененныйАтрибут.OldValue : измененныйАтрибут.NewValue; // Заменяем номер детейла на ключ объекта. Так как номер переприсваевается следующими по порядку детейлу, // в качестве ключа изменения детейла используем тип детейла и его первичного ключа заключенный в между@@ изменениеОбъекта.DetailsChanges[ главноеИзменение.Field.Replace(номерДетейла, $"@{ключДетейла}@")] = GetChangesByPeriodByPK(from, until, ключДетейла, false, recursive); } else { // Это изменение мастера. // Если ссылка на мастра стала нулл, то и изменения не будем собирать, возвращаем нулл. изменениеОбъекта.MastersChanges[главноеИзменение.Field] = измененныйАтрибут.NewValue == "-NULL-" ? null : GetChangesByPeriodByPK(from, until, измененныйАтрибут.NewValue, false, recursive); } } } } } return(изменениеОбъекта); }
public void GetKeyByObjectСравнениеGuid() { Assert.True( PKHelper.EQPK(g1, PKHelper.GetKeyByObject(g1)), "Возвращенный KeyGuid не равен исходному Guid."); }
public void EQPKСравнениеОбъектовСРазнымиGuid() { Assert.True( !PKHelper.EQPK(doft1, doft2), "Объекты с разными Guid сравнены неверно."); }
public void EQPKСравнениеОбъектовСОдинаковымиGuid() { var obj2 = PKHelper.CreateDataObject <DataObjectForTest>(doft0); Assert.True(PKHelper.EQPK(doft0, obj2), "Объекты с одинаковыми Guid сравнены неверно."); }
public void EQPKСравнениеОбъектовСКлючомИБезКлючом() { Assert.True(!PKHelper.EQPK(new object(), doft0), "Объект с ключом и объект без ключа сравнены неверно."); }
public void CreateDataObjectСравнениеКлючей() { Assert.True(PKHelper.EQPK(kg1, doft1), "Метод вернул объект с неверным ключом."); }
public void EQPKСравнениеПустогоОбъектаИСКлючом() { Assert.True(!PKHelper.EQPK(null, doft0), "Пустой объект и объект с ключом сравнены неверно."); }
public void EQPKСравнениеОбъектовБезКлючей() { Assert.True(!PKHelper.EQPK(new object(), new object()), "Объекты без ключей сравнены неверно."); }
public void EQPKСравнениеПустогоОбъектаИБезКлюча() { Assert.True(!PKHelper.EQPK(null, new object()), "Пустой объект и объект без ключа сравнены неверно."); }
public void EQPKСравнениеПустыхОбъектов() { Assert.True(!PKHelper.EQPK(null, null), "Пустые объекты сравнены неверно."); }
public void GetGuidByObjectСравнениеString() { Assert.True( PKHelper.EQPK(str1, PKHelper.GetKeyByObject(str1)), "Возвращенный Guid не равен исходному string."); }
/// <summary> /// Получить объект на заданную дату. /// </summary> /// <param name="date">Дата на которую следует откатить состояние объекта</param> /// <param name="obj">Объект, который откатываем на заданную дату.</param> /// <param name="onlySelfObj">Откатывать только сам объект, т.е. в обратное состояния вернутся все собственные поля объекта и все собственные ссылочные объекты(мастра и детейлы) только ключи</param> /// <param name="forceNullAgregator">Объект вернётся в состояние сразу после заданной даты. /// Если откатываем создание объекта, то возвращаем путой объект с первичным ключом. /// Если объект был удалён и ведётся аудит удаления, то он будет восстановлен со всеми своими собственными полями, иначе если аудит удаления отключен, у удаленного объекта будет проинициализирован только первичный ключ. /// </param> public static void GetObjForDate(DateTime date, ref DataObject obj, bool onlySelfObj = true, bool forceNullAgregator = false) { if (obj != null) { var objType = obj.GetType(); try { obj.DisableInitDataCopy(); // Не кидается исключение о не существовании объекта, если объект был удалён и ведётся аудит удаления, то он будет восстановлен со всеми своими собственными полями, иначе если аудит удаления отключен, у удаленного объекта будет проинициализирован только первичный ключ. DataServiceFactory.AppDataService.LoadObject(new View(objType, View.ReadType.WithRelated), obj, true, false); } catch (Exception ex) { throw new Exception($"Ошибка при попытке вычитать изменнённый объект из БД. {ex.Message}"); } List <AuditEntity> changedAuditEntity; try { var lcs = LoadingCustomizationStruct.GetSimpleStruct(typeof(AuditEntity), AuditEntity.Views.AuditEntityE); lcs.LimitFunction = FunctionBuilder.BuildAnd( #pragma warning disable CS0618 // Используем не дженерик вариант, иначе не работает вычитка FunctionBuilder.BuildEquals(nameof(AuditEntity.ObjectPrimaryKey), obj.__PrimaryKey), #pragma warning restore CS0618 // Тип или член устарел FunctionBuilder.BuildGreater <AuditEntity>(x => x.OperationTime, date)); // Загружаем изменения строго больше даты на которую хотим откатить => получаем объект в состоянии сразу после этой даты. lcs.ColumnsSort = new[] { new ColumnsSortDef(nameof(AuditEntity.OperationTime), SortOrder.Desc) }; changedAuditEntity = DataServiceFactory.AppDataService.LoadObjects(lcs).Cast <AuditEntity>().ToList(); } catch (Exception ex) { throw new Exception( $"Ошибка при попытке загрузить операции изменения {nameof(AuditEntity)} для объекта({obj.__PrimaryKey}). {ex.Message}"); } var auditFieldsLcs = LoadingCustomizationStruct.GetSimpleStruct(typeof(AuditField), ViewForField); foreach (var changeEntity in changedAuditEntity) { if (changeEntity.OperationType != OperationCreateType) { List <AuditField> changedFields; try { // Загружаем набор изменившихся полей из аудита auditFieldsLcs.LimitFunction = FunctionBuilder.BuildEquals <AuditField>(x => x.AuditEntity, changeEntity); changedFields = DataServiceFactory.AppDataService.LoadObjects(auditFieldsLcs) .Cast <AuditField>().ToList(); } catch (Exception ex) { throw new Exception( $"Произошла ошибка при попытке получить набор изменений полей для операции аудита:{PKHelper.GetGuidByObject(changeEntity)}. {ex.Message}"); } //Берём только изменения, вспомогательные объекты LinkedPrimaryKey остаются в основном списке. var onlySelfChangedFields = changedFields.Where(y => y.MainChange == null); foreach (var changedField in onlySelfChangedFields) { var mainChange = changedFields.FirstOrDefault(x => PKHelper.EQPK(x.MainChange, changedField)); if (mainChange == null) { //Если основного изменения нет, то это обычное поле var propertyInfo = objType.GetProperty(changedField.Field); if (propertyInfo != null) { var typeprop = propertyInfo.PropertyType; object value = null; try { if (changedField.OldValue != null) { if (typeprop.IsEnum) { value = EnumCaption.GetValueFor(changedField.OldValue, typeprop); } else if (typeprop == typeof(NullableDateTime)) { value = NullableDateTime.Parse(changedField.OldValue); } else if (typeprop == typeof(NullableInt)) { value = NullableInt.Parse(changedField.OldValue); } else { value = Convert.ChangeType(changedField.OldValue, typeprop, CultureInfo.InvariantCulture); } } propertyInfo.SetValue(obj, value); } catch (Exception ex) { var errorText = value != null ? $"AuditField:{PKHelper.GetGuidByObject(changedField)} Ошибка при попытке установить значение поля {value} в объект {objType.Name}:{PKHelper.GetGuidByObject(obj)} поле {changedField.Field}" : $"AuditField:{PKHelper.GetGuidByObject(changedField)} Ошибка при попытке преобразовать значение поля {changedField.OldValue} в тип {typeprop.Name}"; throw new Exception($"{errorText}. {ex.Message}"); } } else { throw new Exception( $"Ошибка - не найдено поле {changedField.Field} в объекте {objType.Name}."); } } else { // Есть основное изменение, значит это изменение ссылочного объекта. // Только если изменилась ссылка if (mainChange.OldValue != mainChange.NewValue) { // В аудите детейл отличается от мастера тем, что у него приписывается в скобках позиция if (Regex.IsMatch(changedField.Field, "[ ][(][0-9]+[)]$")) { // Это изменение детейла объекта. var separateIndex = changedField.Field.IndexOf(" ", StringComparison.Ordinal); var detailNameFromField = changedField.Field.Substring(0, separateIndex); var propertyInfo = objType.GetProperty(detailNameFromField); if (propertyInfo != null) { if (propertyInfo.GetValue(obj) is DetailArray detailValue) { if (changedField.OldValue == "-NULL-") { var key = new KeyGuid(mainChange.NewValue); try { detailValue.RemoveByKey(key); } catch (Exception ex) { throw new Exception( $"Ошибка при попытке удалить объект с ключом {key} из детейла {detailNameFromField} в объекте {objType.Name}. {ex.Message}"); } } else { var detailItemType = detailValue.ItemType; var oldDetailObj = Helper.CreateDataObject(detailItemType, mainChange.OldValue); try { detailValue.AddObject(oldDetailObj); } catch (Exception ex) { throw new Exception( $"Ошибка при добавить объект с ключом {PKHelper.GetGuidByObject(oldDetailObj)} в детейл {detailNameFromField} в объекте {objType.Name}. {ex.Message}"); } } } } else { throw new Exception( $"Ошибка - не найден детейл {detailNameFromField} в объекте {objType.Name}."); } } else { // Это изменение мастера объекта. var propertyInfo = objType.GetProperty(changedField.Field); if (propertyInfo != null) { //Это свойство является агрегатором, для детейла var itIsAgregator = propertyInfo.GetCustomAttribute <AgregatorAttribute>() != null; if (changedField.OldValue == "-NULL-" || forceNullAgregator && itIsAgregator) { //Если свойство является агрегатором для детейла, то в последующих витках рекурсии всегда возвращаем нулл для такого поля, во избежание циклических ссылок. propertyInfo.SetValue(obj, null); } else { var typeprop = propertyInfo.PropertyType; var oldMasterObj = Helper.CreateDataObject(typeprop, mainChange.OldValue); try { propertyInfo.SetValue(obj, oldMasterObj); } catch (Exception ex) { throw new Exception( $"Ошибка при попытке установить свойство мастера {changedField.Field} в объекте {objType.Name}. {ex.Message}"); } } } else { throw new Exception( $"Ошибка - не найден мастер {changedField.Field} в объекте {objType.Name}."); } } } } } } else { // Если откатываем создание объекта, то возвращаем путой объект с первичным ключом. obj = Helper.CreateDataObject(objType, obj.__PrimaryKey); } } // На этом этапе основной объект и все его собственные поля и зависимые сущности возвращены на дату // Получаем мастера и откатываем их поля, рекурсивно вызывая этот метод // Получаем детейлы объекта и откатываем их поля, рекурсивно вызывая этот метод if (!onlySelfObj && changedAuditEntity.Any()) { var objProperties = objType.GetProperties(); foreach (var property in objProperties) { var typeprop = property.PropertyType; if (typeprop.IsSubclassOf(typeof(DataObject))) { //Перебираем все мастера var masterValue = property.GetValue(obj) as DataObject; GetObjForDate(date, ref masterValue, false, true); } else if (typeprop.IsSubclassOf(typeof(DetailArray))) { //Перебираем все детейлы if (property.GetValue(obj) is DetailArray detailValue) { var detailObjects = detailValue.GetAllObjects(); foreach (var dataObject in detailObjects) { var currentObj = dataObject; GetObjForDate(date, ref currentObj, false, true); } } } } } } }
/// <summary> /// Обработка объекта /// </summary> /// <param name="obj">объект, который пришел</param> /// <param name="state">тип изменения, входящего объекта</param> /// <param name="type">тип объекта, в который преобразуем</param> /// <param name="mapper">маппер для преобразования</param> /// <param name="attrs">список изменяемых свойств</param> /// <param name="source">Источник изменений</param> /// <param name="arrToUpd">Список обновляемых объектов данных</param> /// <param name="arrConformity">Список обновляемых объектов синхронизации</param> private void ProcessObject(SyncXMLDataObject obj, tState state, Type type, IPropertyMapperWithChangedAttrs mapper, List <string> attrs, Source source, ref List <DataObject> arrToUpd, ref Dictionary <string, List <DataObject> > arrConformity) { if (obj == null) { return; } var view = mapper.GetView(); var nameType = type.FullName; var otype = arrConformity[sObjectType].Cast <ObjectType>().FirstOrDefault(x => x.name == nameType) ?? _syncDS.Query <ObjectType>(ObjectType.Views.ObjectTypeE) .FirstOrDefault(x => x.name == nameType) ?? new ObjectType { name = nameType, id = type.Name }; if (otype.GetStatus() == ObjectStatus.Created) { arrConformity[sObjectType].Add(otype); } Conformity conformity = null; if (otype.GetStatus() != ObjectStatus.Created && source.GetStatus() != ObjectStatus.Created) { conformity = _syncDS.Query <Conformity>(Conformity.Views.ConformityE).FirstOrDefault(x => x.Source.__PrimaryKey.Equals(source.__PrimaryKey) && x.Type.__PrimaryKey.Equals(otype.__PrimaryKey) && x.pkSource.Equals(obj.Guid)); } if (state != tState.deleted) //создание/изменение { DataObject dest = null; if (conformity != null) //ищем по pk { dest = GetDataObject(type, view, conformity.pkDest); } else { dest = GetDataObject(type, view, obj.Guid); } if (dest == null) //ищем по альтернативному ключу { var queryAlt = mapper.GetAltKey(obj, _defDS, _syncDS, source, ref arrToUpd, ref arrConformity); dest = queryAlt?.FirstOrDefault(); if (queryAlt != null && dest != null) { LogService.LogInfo($"BusMessageHandlerService: Удалось найти объект(pk-{obj.Guid}) по альтернативному ключу для типа {nameType}. Сопоставленный объект объект(pk-{dest.__PrimaryKey})"); } } if (dest == null) { dest = (DataObject)Activator.CreateInstance(type); } dest.GetStatus(); dest = mapper.Map(obj, dest, attrs); // Проверяем было ли помещено создание объекта на апдейт. Если да, то такой объект уже считается существующим и статус нового объекта с таким же ключом меняется на Altered. var alreadyExistsCreatedObj = arrToUpd.Exists(x => PKHelper.EQPK(x, dest) && x.GetStatus(false) == ObjectStatus.Created); if (alreadyExistsCreatedObj) { dest.SetLoadingState(LoadingState.Loaded); dest.SetStatus(ObjectStatus.Altered); } arrToUpd.Add(dest); //заполнение мастеров/////////////////////////////////////////////////////////////////////////////// mapper.SetMasters(obj, dest, attrs, _defDS, _syncDS, source, ref arrToUpd, ref arrConformity); if (conformity == null) { conformity = new Conformity { Source = source, Type = otype, pkSource = obj.Guid, pkDest = new Guid(dest.__PrimaryKey.ToString()) }; arrConformity[sConformity].Add(conformity); } } else //удаление { if (conformity != null) { var count = _syncDS.Query <Conformity>(Conformity.Views.ConformityE).Count(x => x.Type.__PrimaryKey.Equals(otype.__PrimaryKey) && x.pkDest.Equals(conformity.pkDest)); if (count >= 1) { conformity.SetStatus(ObjectStatus.Deleted); arrConformity[sConformity].Add(conformity); } if (count == 1) { var dest = GetDataObject(type, view, conformity.pkDest); if (dest != null) { dest.SetStatus(ObjectStatus.Deleted); arrToUpd.Add(dest); } } } } }