Проверка и использование Entity Framework - PullRequest
13 голосов
/ 19 ноября 2008

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

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

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

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

Ответы [ 5 ]

2 голосов
/ 23 декабря 2010

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

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

ТЛ; др

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

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

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

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

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

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

0 голосов
/ 08 ноября 2010

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

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

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

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

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

0 голосов
/ 24 сентября 2009

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

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);
}
0 голосов
/ 12 августа 2010

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

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

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

0 голосов
/ 19 августа 2009

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

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

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

Удачи

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...