2008-11-19 20 views
13

Mam świadomość zdarzenia AssociationChanged, jednak zdarzenie to jest wywoływane po skojarzeniu. Nie ma zdarzenia AssociationChanging. Tak więc, jeśli chcę rzucić wyjątek z jakiegoś powodu sprawdzania poprawności, w jaki sposób mogę to zrobić i wrócić do mojej pierwotnej wartości?Entity Framework Validation & usage

Chciałbym również ustawić wartości domyślne dla mojej jednostki na podstawie informacji od innych podmiotów , ale należy to zrobić tylko wtedy, gdy wiem, że dane urządzenie zostało wstawione do bazy danych. Jak odróżnić ten obiekt od instancji, ponieważ ma on zostać wypełniony na podstawie istniejących danych? Czy powinienem wiedzieć? Czy ta logika biznesowa powinna być poza logiką biznesową mojej jednostki?

Jeśli tak, to czy powinienem zaprojektować klasy kontrolerów, aby zawinąć wszystkie te encje? Obawiam się, że jeśli dostarczę jednostkę, chcę, aby klient uzyskał dostęp do jej właściwości, ale chcę zachować ścisłą kontrolę nad sprawdzaniem, jak są one ustawione, domyślne itp. Każdy przykład widziałem kontekst odniesienia, który jest poza moim świadectwem częściowej oceny klasowej, prawda?

BTW, patrzyłem na EFPocoAdapter i przez całe życie nie mogę ustalić, jak zapełniać listy z mojej klasy POCO ... Czy ktoś wie, jak mogę uzyskać kontekst z klasy EFPoco?

Odpowiedz

0

Odnośnie pierwszego pytania, po prostu wprowadziłbym zmiany w stowarzyszeniach jako logikę biznesową. Na przykład, jeśli dodasz Wychowawca ze stwardnieniem Studenta, nie sumują studentów jak

aTeacher.Students.Add(new Student) 

zamiast utworzyć metodę AddStudent

public Student AddNewStudent(string name, string studentID) 
{ 

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

ten sposób użytkownik ma pełną kontrolę nad tym, kiedy związki są zmieniane. Co oczywiście powstrzymuje innego programistę przed bezpośrednim dodaniem ucznia? Po stronie Studenta możesz ustawić Ustawiciela Nauczyciela na prywatny (i zmienić konstruktor, aby zaakceptował nauczyciela lub podobnego). Po stronie nauczyciela, jak sprawić, by kolekcja Studenci nie była wstawiana? Nie jestem pewien ... może przekształcając go w niestandardową kolekcję, która nie akceptuje wstawek.

Odnośnie drugiej części pytania prawdopodobnie można użyć zdarzeń OnVarNameChanging. Jeśli EntityState jest "New", możesz zastosować swoją logikę, która pobiera rzeczywiste wartości.

Występuje także zdarzenie, które jest uruchamiane podczas zapisywania zmian (OnSavingChanges?), Których można użyć do określenia, które obiekty są nowe i ustawić niektóre wartości.

Ale najprostszym rozwiązaniem jest zawsze ustawić wartości domyślne w konstruktorze i zostaną one nadpisane, jeśli dane zostaną załadowane z bazy danych.

Powodzenia

0

utworzyć fabrykę, która produkuje instancje dla Ciebie w zależności od potrzeb, takich jak:

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

To poważny brak nie mają AssociationChanging (która dziedziczy od CancelEventArgs) zdarzeń.

Niepokoi mnie również bardzo dużo, dlatego zgłosiłem to do Microsoft Connect Please vote here!

I BTW, ja też, że to też głupie, że PropertyChangingEventArgs nie dziedziczy CancelEventArgs, gdyż anulowanie z wyjątkiem jest nie zawsze jest to eleganckie rozwiązanie, poza tym rzucanie wyjątków kosztuje więcej wydajności niż wywołanie OnPropertyChangingEvent, a następnie sprawdzenie zwróconego e.Cancel, więc kosztuje mniej niż podniesienie PropertyChangingEvent, które i tak nazywasz obiema.
Również wyjątek może zostać wyrzucony w programie obsługi, a nie oznaczać e.Anuluj jako prawdziwy, dla tych, którzy nalegają, aby przejść drogę wyjątku. Vote Here.

+1

PropertyChangingEventArgs nie ma związku z CancelEventArgs. Mają czasy, w których muszą być używane wyłącznie do różnych celów. Wymuszenie dziedziczenia spowodowałoby niepotrzebne komplikacje i frustrację (ścisłe połączenie ich ze sobą). Istnieje PropertyChangingEvent i PropertyChangedEvent i uważam, że spełniają one pożądaną funkcjonalność bez wprowadzania w nich zmian (nie wspominając o tym, że przełamie kompatybilność .NET 1.1 z .NET 4.0). – TamusJRoyce

+0

@TamusJRoyce, OK, zgadzam się, nie powinien on dziedziczyć po 'CancelEventArgs', ale to, co powinien zrobić, to moja druga prośba, która podaje wartość kandydata (którą można łatwo zdobyć, pobierając aktualne atrybuty metody ze znaczącym kwota kosztów wykonania). – Shimmy

0

Aby możliwe było udzielenie odpowiedzi na część pytania lub wyjaśnienie odpowiedzi ADB, użytkownik obiektu ObjectStateManager.GetObjectStateEntry może znaleźć stan obiektów i wpisać niestandardową logikę domyślną.

SaveChanges to metoda kontekstu, z której można korzystać, lub SavingChanges to zdarzenie, które ma miejsce przed wywołaniem SaveChanges.

Można zastąpić SaveChanges i base.SaveChanges tylko zadzwonić, jeśli nie chcesz, aby przerwać zmiana

Istnieje również ObjectMaterialized wydarzeniem dla kontekstu.

między dwoma można trzymać wszystkie swoje walidacji i tworzenia kodu w jednym miejscu, które mogą być odpowiednie, jeśli są złożone i obejmują wartości innych przedmiotów itp ..

2

To w odpowiedzi na komentarz zostawiłem . Mam nadzieję, że to odpowiada na twoje pytanie, Shimmy. Po prostu skomentuj, a skracam lub usuwam, jeśli nie odpowiada na twoje pytanie.

Potrzebne będą interfejsy INotifyPropertyChanging i INotifyPropertyChanged, które zostaną zaimplementowane w klasie (chyba że jest to coś w rodzaju obiektu struktury encji, który moim zdaniem implementuje je wewnętrznie).

Przed ustawieniem wartości tej właściwości należy podnieść wartość zdarzenia NotifyPropertyChanging.PropertyChanging, używając nazwy właściwości w konstruktorze PropertyChangingEventArgs.

Po ustawieniu tej wartości należy podnieść zdarzenie NofityPropertyChanged.PropertyChanged, ponownie używając nazwy właściwości, która jest wywoływana w konstruktorze PropertyChangedEventArgs.

Następnie należy obsłużyć zdarzenia PropertyChanging i PropertyChanged. W zdarzeniu PropertyChanging należy buforować wartość. W zdarzeniu PropertyChanged można porównać i wyrzucić wyjątek.

Aby uzyskać właściwość z argumentów zdarzenia PropertyChanging/PropertyChanged, należy użyć metody relfect.

// 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 

Zauważ, jak używam PreventRecursion, który jest boolean Zapomniałem dodać powyżej tych metod? Po przywróceniu właściwości do poprzedniej wartości zdarzenia te zostaną przywołane.

tl; dr

Teraz można czerpać pojedynczego zdarzenia, które dziedziczy INotifyPropertyChanged, ale używa argumentu, który posiada obiekt reprezentujący poprzednią wartość, jak nazwa właściwości.A to ograniczyłoby liczbę zdarzeń uruchamianych do jednego, mają podobną funkcjonalność i mają wsteczną kompatybilność z INotifyPropertyChanged.

Ale jeśli chcesz zająć się czymkolwiek, zanim właściwość zostanie ustawiona (powiedzmy, że właściwość powoduje nieodwracalną zmianę lub musisz ustawić inne właściwości przed ustawieniem tej zmiennej, w przeciwnym razie zostanie zgłoszony wyjątek) nie będziesz w stanie Zrób to.

Ogólnie rzecz biorąc, ta metoda jest bardzo starym sposobem robienia rzeczy. Chciałbym wziąć odpowiedź od Poker Villiana i podać nieprawidłowe dane. Ale nie zezwalaj na zapisywanie do bazy danych.

Entity Framework ma znakomity kod do walidacji. Dodajesz walidację do swoich właściwości za pomocą atrybutów. A potem dba o pracę przetwarzania tych atrybutów. Następnie możesz utworzyć właściwość o nazwie IsValid, która wywołuje specyficzne sprawdzanie Entity Framework. Rozróżnia także błędy w polu (np. Wpisywanie niewłaściwych znaków lub zbyt długi ciąg znaków) oraz błędy klas (np. Brakujące dane lub klucze powodujące konflikt).

Następnie można powiązać IsValid z kontrolą walidacji i wyświetlają czerwoną bańkę podczas wprowadzania nieprawidłowych danych. Lub możesz sam wdrożyć weryfikację IsValid. Ale jeśli IsValid ma wartość false, zdarzenie SaveChanges będzie musiało anulować zapisywanie.

btw. Podany kod nie zostanie skompilowany i jest tylko pseudokodami (mieszanie vb i C#). Uważam jednak, że jest on znacznie bardziej opisowy niż samo C# - pokazuje dokładnie to, co jest obsługiwane.