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

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

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

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

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
13
0
1 965
5

Ответы 5

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

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?), Которое можно использовать для определения новых объектов и установки некоторых значений.

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

Удачи

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

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);
}

Отсутствие события AssociationChanging (наследуемого от CancelEventArgs) - серьезный недостаток.

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

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

PropertyChangingEventArgs не имеет отношения к CancelEventArgs. У них бывают времена, когда их нужно использовать исключительно для разных целей. Принудительное наследование вызвало бы ненужные осложнения и разочарования (плотно связав их вместе). Есть PropertyChangingEvent и PropertyChangedEvent, и я считаю, что они удовлетворяют желаемую функциональность без внесения в них изменений (не говоря уже о том, что это нарушит совместимость .NET 1.1 с .NET 4.0).

TamusJRoyce 06.11.2010 07:27

@TamusJRoyce, хорошо, я согласен, он не должен наследовать от CancelEventArgs, но он должен делать другой мой запрос, который предоставляет значение кандидата (который проще всего получить, получив текущие атрибуты метода со значительной производительностью Стоимость).

Shimmy Weitzhandler 20.12.2010 12:15

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

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

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

Также существует событие ObjectMaterialized для контекста.

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

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

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

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

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

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

Чтобы получить свойство из аргументов события PropertyChanging / 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 - логическое значение, которое я забыл добавить выше этих методов? Когда вы сбросите свойство обратно к его предыдущему значению, эти события будут отозваны.

tl; dr

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

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

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

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

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

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

Другие вопросы по теме