Проверка и использование платформы Entity Framework

Я знаю, что есть событие AssociationChanged, однако это событие срабатывает после создания ассоциации. Событие AssociationChanging отсутствует. Итак, если я хочу исключить исключение из-за некоторой причины проверки, как мне это сделать и вернуться к исходному значению?

Кроме того, я хотел бы использовать значения по умолчанию для моего объекта на основе информации от других объектов , но делать это только тогда, когда я знаю, что для входа в базу данных задано значение entitiy. Как я могу объяснить разницу между тем и тем, что получает объект, потому что он будет заполнен на основе существующих данных? Должен ли я знать? Это сообразительная бизнес-логика, которая должна быть за пределами моей бизнес-логики?

Если это так, то должен ли я разрабатывать классы контроллеров для переноса всех этих объектов? Я беспокоюсь, что если я верну сущность, я хочу, чтобы клиент получил доступ к свойствам, но я хочу сохранить жесткий контроль над проверками на то, как они установлены, дефолт и т.д. Каждый пример, который я видел, ссылается на контекст, который находится за пределами частичной проверки моего enity, верно?

Кстати, я посмотрел на EFPocoAdapter, и на всю жизнь я не могу определить, как заполнять списки из моего класса POCO... кто-нибудь знает, как я попадаю в контекст из класса EFPoco?

Ответы

Ответ 1

Это ответ на комментарий, который я оставил. Надеюсь, это ответит на ваш вопрос, Шимми. Просто комментарий, и я сокращу его или удалю, если он не ответит на ваш вопрос.

Вам потребуются как INotifyPropertyChanging, так и INotifyPropertyChanged интерфейсы, которые будут реализованы в вашем классе (если только это не похоже на объект фреймворка сущности, который, как я считаю, реализует их внутренне).

И прежде чем вы установите значение для этого свойства, вам нужно поднять событие NotifyPropertyChanging.PropertyChanging, используя имя свойства в конструкторе PropertyChangingEventArgs.

И после того, как вы установите это значение, вам нужно поднять событие NofityPropertyChanged.PropertyChanged, снова используя имя свойства, которое создается в конструкторе PropertyChangedEventArgs.

Затем вам нужно обработать события PropertyChanging и PropertyChanged. В событии PropertyChanging вам нужно кэшировать значение. В событии PropertyChanged вы можете сравнить и выбросить исключение.

Чтобы получить свойство из аргументов eventChanging/PropertyChanged, вам нужно использовать функцию relfection.

// PropertyName is the key, and the PropertyValue is the value.
Dictionary <string, object> propertyDict = new Dictionary<object, object>();

    // Convert this function prototype to C# from VBNet.  I like how Handles is descriptive.
    Public Sub PropertyChanging(sender As object, e As PropertyChangingEventArgs) Handles Foo.PropertyChanging
    {
      if (sender == null || preventRecursion)
      {
        return;
      } // End if

      Type senderType = sender.GetType();
      PropertyInfo info = senderType.GetProperty(e.PropertyName);
      object propertyValue = info.GetValue(sender, null);

      // Change this so it checks if e.PropertyName already exists.
      propertyDict.Add(e.PropertyName, propertyValue);
    } // End PropertyChanging() Event

     // Convert this function prototype to C# from VBNet.  I like how Handles is descriptive.
    Public Sub PropertyChanged(sender As object, e As PropertyChangedEventArgs) Handles Foo.PropertyChanged
    {
      if (sender == null || preventRecursion)
      {
        return;
      } // End if

      Type senderType = sender.GetType();
      PropertyInfo info = senderType.GetProperty(e.PropertyName);
      object propertyValue = info.GetValue(sender, null);

      // Change this so it makes sure e.PropertyName exists.
      object oldValue = propertyDict(e.PropertyName);
      object newValue = propertyValue;

      // No longer needed.
      propertyDict.Remove(e.PropertyName);

      if (/* some condition */)
      {
        try {
          preventRecursion = true;
          info.SetValue(oldValue, null);
          Throw New Exception();
        } finally {
          preventRecursion = false;
        } // End try
      } // End if
    } // End PropertyChanging() Event

Обратите внимание, как я использую PreventRecursion, который является логическим, я забыл добавить выше этих методов? Когда вы reset свойство вернется к своему предыдущему значению, эти события будут вызваны.

ТЛ; дг

Теперь вы можете получить одно событие, которое наследуется от INotifyPropertyChanged, но использует аргумент, который содержит объект, представляющий предыдущее значение, а также имя свойства. И это уменьшит количество запущенных событий до одного, будет иметь аналогичную функциональность и будет иметь обратную совместимость с INotifyPropertyChanged.

Но если вы хотите обработать что-либо до того, как свойство будет установлено (скажем, свойство делает необратимое изменение или вам нужно настроить другие свойства перед установкой этой переменной, в противном случае будет выбрано исключение), вы не сможете сделать что.

В целом, этот метод - очень старый способ делать вещи. Я бы ответил на Poker Villian и имел недействительные данные, которые можно ввести. Но запретите сохранение в базе данных.

В Entity Framework есть отличный код для проверки. Вы добавляете подтверждение к своим свойствам через атрибуты. И затем он заботится о работе по обработке этих атрибутов. Затем вы можете создать свойство IsValid, которое вызывает специфическую проверку Entity Framework. Он также различает как полевые ошибки (например, ввод неправильных символов, либо слишком длинная строка), так и ошибки класса (например, отсутствие данных или конфликтующие ключи).

Затем вы можете привязать IsValid к проверке проверки, и они будут отображать красный пузырь, пока будут введены неверные данные. Или вы можете просто реализовать проверку IsValid самостоятельно. Но если IsValid является ложным, для события SaveChanges потребуется отменить сохранение.

кстати. Предоставленный код не будет компилироваться и только псевдокод (смешение vb и С#). Но я считаю, что это гораздо более описательно, чем только С# - показывая точно, что обрабатывается.

Ответ 2

Что касается вашего первого вопроса, я бы просто реализовал изменения в ассоциациях как бизнес-логику. Например, если вы добавляете класс Учителя с несколькими учениками, не добавляйте таких учеников, как

aTeacher.Students.Add(new Student)

вместо этого создайте метод AddStudent

public Student AddNewStudent(string name, string studentID)
{

    Student s = new Student( name, studentID);
    s.Teacher = this; // changes the association
    return s;
}

Таким образом, вы полностью контролируете изменения ассоциаций. Конечно, что мешает другому программисту добавить ученика напрямую? На стороне Студента вы можете настроить установщика Учителя на личную (и изменить конструктор, чтобы принять учителя или подобное). На стороне учителя, как сделать сбор студентов не вставными? Я не уверен... может превратить его в пользовательскую коллекцию, которая не принимает вставки.

Что касается второй части вашего вопроса, возможно, вы можете использовать события OnVarNameChanging. Если EntityState является "New", вы можете применить свою логику, которая извлекает реальные значения.

Также существует событие, которое срабатывает при сохранении изменений (OnSavingChanges?), которые вы могли бы использовать, чтобы определить, какие объекты являются новыми, и установить некоторые значения.

Но, возможно, самым простым решением является всегда устанавливать значения по умолчанию в конструкторе, и они будут перезаписаны, если данные будут загружены из БД.

Удачи.

Ответ 3

Создайте factory, который создает экземпляры для вас в зависимости от ваших потребностей:

getStudent(String studentName, long studentId, Teacher teacher) {
    return new Student(studentName, studentId);
}

getStudentForDBInseration(String studentName, long studentId, Teacher teacher) {
    Student student = getStudent(studentName, studentId);
    student = teacher;
    //some entity frameworks need the student to be in the teachers student list
    //so you might need to add the student to the teachers student list
    teacher.addStudent(student);
}

Ответ 4

Это серьезный недостаток в отсутствии ассоциацииChanging (которая наследует от CancelEventArgs) событие.

Меня это тоже очень беспокоит, поэтому я сообщил об этом Microsoft Connect Пожалуйста, проголосуйте здесь!

И BTW, я также думаю, что это тоже глупо, что PropertyChangingEventArgs не наследует CancelEventArgs, так как отмена с исключением не всегда является изящным решением, кроме того, исключение для исключения исключений требует большей производительности, чем вызов OnPropertyChangingEvent, а затем проверка на возвращаемое e.Cancel, так это стоит меньше, чем повышение PropertyChangingEvent, которое вы так или иначе называете их обоими.
Кроме того, исключение может быть выбрано в обработчике в любом случае вместо того, чтобы маркировать e.Cancel как истину, для тех, кто настаивает на том, чтобы идти по пути исключения. Проголосуйте здесь.

Ответ 5

Чтобы ответить на часть вашего вопроса или изложить ответ АБР, вы можете ObjectStateManager.GetObjectStateEntry найти состояние сущностей и написать свою настраиваемую логику по умолчанию.

SaveChanges - это метод в контексте, который вы можете использовать, или SavingChanges - это событие, которое происходит до вызова SaveChanges.

Вы можете переопределить SaveChanges и только вызвать base.SaveChanges, если вы не хотите прервать изменение

Для контекста также есть событие ObjectMaterialized.

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