Поиск всех объектов с определенным свойством и их записями

Я использую EF Code First, но мои модели НЕ имеют отношений (PK-FK). Поэтому я пытаюсь найти способ обойти это, используя EF6 Reflections, чтобы избежать удаления записи, которая будет иметь отношения (то же имя свойства).

  • Поиск всех объектов моего контекста, в которых есть какое-либо определенное свойство (FK);
  • Для каждого найденного объекта проверьте, есть ли у этого объекта какая-либо запись;
  • Если это правда, вместо удаления моей записи установите для свойства «Отменено» значение true;
  • Если это ложно, оставьте состояние объекта удаленным и сохраните мои изменения контекста;

    public override int SaveChanges()
    {
        foreach (var myEntity in ChangeTracker.Entries<IAuditable>())
        {
            if (myEntity.State == EntityState.Deleted)
            {
                ObjectContext objContext = ((IObjectContextAdapter)this).ObjectContext;
                var container = objContext.MetadataWorkspace.GetEntityContainer(objContext.DefaultContainerName, DataSpace.CSpace);
    
                var objectStateEntry = ((IObjectContextAdapter)this).ObjectContext.ObjectStateManager.GetObjectStateEntry(myEntity.Entity);
                var entityKeys = objectStateEntry.EntityKey.EntityKeyValues;
                var entity = myEntity;
                var hasAnyFk = false;
                foreach (var entityKey in entityKeys)
                {
                    if (hasAnyFk)
                    {
                        break;
                    }
    
                    var keyName = entityKey.Key;
                    foreach (var entitySet in container.EntitySets)
                    {
                        hasAnyFk = entitySet.ElementType.Members.Any(es => es.Name == keyName);
                        if (hasAnyFk)
                        {
                            break;
                        }
                    }
                }
    
                if (hasAnyFk)
                {
                    var deletedProperty = myEntity.OriginalValues.PropertyNames.Where(p => myEntity.Property(p).Name == "Deleted").FirstOrDefault();
                    if (deletedProperty != null)
                    {
                        myEntity.State = EntityState.Modified;
                        myEntity.CurrentValues[deletedProperty] = true;
                    }
                }
            }
        }
    

    вернуть base.SaveChanges(); }


person Rubens Mussi Cury    schedule 09.12.2016    source источник
comment
Если вы сначала делаете код, почему бы просто не добавить отношения? Это кажется действительно странным шаблоном для выбора. В любом случае, если ваши классы EF находятся в одной сборке, я полагаю, вы можете сканировать сборку на наличие любых классов, имеющих указанное свойство. Вы захотите кэшировать всю эту информацию, чтобы не сканировать каждый раз.   -  person stephen.vakil    schedule 09.12.2016
comment
@stephen.vakil, даже добавляя отношения, я не хочу использовать каскадные функции. Я думаю, это не странно, учитывая то, что я хочу сделать - установить флаги свойств вместо того, чтобы буквально удалять запись. Установка отношений не решит мою потребность.   -  person Rubens Mussi Cury    schedule 09.12.2016
comment
Это поможет. Один из способов — просканировать всю сборку на наличие полей с одинаковыми именами. В другом вы можете запросить свойства навигации, используя встроенные библиотеки EF. Вам не нужно включать каскадное удаление в EF.   -  person stephen.vakil    schedule 09.12.2016
comment
@stephen.vakil действительно, это помогло бы, но в приложении не установлены правильные отношения, и я пытаюсь найти способ избежать неожиданных удалений. Если у вас есть лучший подход, это будет очень кстати.   -  person Rubens Mussi Cury    schedule 09.12.2016
comment
Посмотрите System.Data.Metadata.Edm и примеры запросов к нему, например. stackoverflow.com/ вопросы/15718301/   -  person stephen.vakil    schedule 09.12.2016
comment
@stephen.vakil Я ценю твои подсказки. Если можно, посмотрите мой обновленный пост. Моя единственная проблема сейчас заключается в том, как сделать Select, чтобы проверить, есть ли у найденного объекта какая-либо запись. hasAnyFk = entitySet.ElementType.Members.Any(es => es.Name == keyName); if (hasAnyFk) { ?? How to make a dynamic select using this entity ?? }   -  person Rubens Mussi Cury    schedule 12.12.2016
comment
После вашего редактирования проблема больше не ясна. Теперь вопрос в основном заключается в описании требования и фрагменте кода, который его выполняет (или не выполняет? - но это уже не ясно).   -  person Gert Arnold    schedule 12.12.2016
comment
@ Герт Арнольд, единственное, что я сделал в своем выпуске, это собрал весь код и включил то, что я просил в своих двух первых темах. То, что вы ответили, было хорошим, и я очень ценю это, но обратите внимание, что ваш код относится к темам 3 и 4 моего вопроса.   -  person Rubens Mussi Cury    schedule 12.12.2016
comment
Конечно, это нормально, просто из вашего кода сложно понять, с какой частью у вас все еще возникают проблемы. Кстати, я думаю, что добавление отношений в модель класса — более безопасный способ контроля удалений, чем сопоставление имен свойств. Это, безусловно, значительно упрощает жизнь не только при удалении, но и при выполнении запросов.   -  person Gert Arnold    schedule 12.12.2016
comment
У меня нет вопросов по поводу того, что размещение отношений поможет и сделает это намного проще... но пока я не могу этого сделать. Это временное решение. Если у вас есть что предложить, буду признателен.   -  person Rubens Mussi Cury    schedule 12.12.2016


Ответы (1)


Вы можете справиться с этим, это перегрузка SaveChanges:

public override int SaveChanges()
{
    foreach (var entry in this.ChangeTracker.Entries().Where(e => e.State == 
                                   System.Data.Entity.EntityState.Deleted).ToList())
    {
        var delPropName = "IsDeleted";
        if (entry.OriginalValues.PropertyNames.Contains(delPropName))
        {
            var delProp = entry.Property(delPropName);
            delProp.CurrentValue = true;
            entry.State = System.Data.Entity.EntityState.Modified;
        }
    }
    return base.SaveChanges();
}

Здесь entry.OriginalValues.PropertyNames используется для проверки существования свойства в объекте, затем устанавливается его значение, а состояние записи изменяется на Modified. Обратите внимание, что я перебираю this.ChangeTracker.Entries() после применения ToList(), в противном случае содержимое коллекции изменяется при ее переборе.

person Gert Arnold    schedule 10.12.2016
comment
Спасибо за ваш ответ. Однако я уже сделал эту часть - проверил удаленное свойство и установил true вместо удаления записи. Моя основная задача состоит в следующем: - Поиск всех объектов моего контекста, в которых есть какое-либо конкретное свойство (FK); - Для каждого найденного объекта проверьте, есть ли у этого объекта какая-либо запись;*. Если у меня нет связанной записи с таким же ПК, я могу удалить. - person Rubens Mussi Cury; 12.12.2016
comment
Есть идеи, как это сделать в Efcore? entry.OriginalValues.PropertyNames недоступны - person Hamza Khanzada; 30.01.2021