entity-framework - first - entity framework ya
ValidaciĆ³n y uso de Entity Framework (5)
Con respecto a su primera pregunta, simplemente implementaría los cambios a las asociaciones como lógica de negocios. Por ejemplo, si agrega una clase de profesor con varios alumnos, no agregue alumnos como
aTeacher.Students.Add(new Student)
en su lugar, crea un método AddStudent
public Student AddNewStudent(string name, string studentID)
{
Student s = new Student( name, studentID);
s.Teacher = this; // changes the association
return s;
}
De esta forma, usted tiene control total sobre cuándo se modifican las asociaciones. Por supuesto, ¿qué impide que otro programador agregue un estudiante directamente? En el lado del Estudiante, puede configurar el Organizador de profesores en privado (y cambiar el constructor para aceptar un profesor o similar). En el lado del profesor, ¿cómo hacer que la colección de Estudiantes no sea insertable? No estoy seguro ... tal vez transformarlo en una colección personalizada que no acepte insertos.
Con respecto a la segunda parte de su pregunta, probablemente pueda usar los eventos OnVarNameChanging. Si EntityState es ''Nuevo'', entonces puede aplicar su lógica que recupera los valores reales.
También hay un evento que se activa al guardar los cambios (OnSavingChanges?) Que podría usar para determinar qué objetos son nuevos y establecer algunos valores.
Pero tal vez la solución más simple es establecer siempre los valores predeterminados en el constructor y se sobrescribirán si los datos se cargan desde el DB.
Buena suerte
Soy consciente de que hay un evento AssociationChanged, sin embargo, este evento se dispara después de que se realiza la asociación. No hay evento AssociationChanging. Entonces, si deseo lanzar una excepción por algún motivo de validación, ¿cómo hago esto y vuelvo a mi valor original?
Además, me gustaría establecer valores predeterminados para mi entidad en función de la información de otras entidades, pero hago esto solo cuando sé que la entidad se instancia para la inserción en la base de datos . ¿Cómo puedo saber la diferencia entre eso y el objeto que se instancia porque está a punto de ser poblado en base a los datos existentes? ¿Se supone que debo saber? ¿Es esa lógica empresarial consi- derada la que debería estar fuera de la lógica empresarial de mi entidad?
Si ese es el caso, entonces ¿debería diseñar clases de controlador para envolver todas estas entidades? Mi preocupación es que si devuelvo una entidad, quiero que el cliente tenga acceso a las propiedades, pero quiero retener un control estricto sobre las validaciones sobre cómo están configuradas, predeterminadas, etc. Cada ejemplo que he visto hace referencia al contexto, que está fuera de mi validación de clase parcial de enity, ¿verdad?
Por cierto, miré el EFPocoAdapter y por mi vida no puedo determinar cómo llenar listas de dentro de mi clase POCO ... ¿Alguien sabe cómo llego al contexto de una clase EFPoco?
Cree una fábrica que produzca instancias para usted según su necesidad, como:
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);
}
Es una falta grave no tener un evento AssociationChanging (que hereda de CancelEventArgs
).
También me molesta mucho, por lo tanto, informé de esto a Microsoft Connect ¡ Por favor vote aquí!
Y por cierto, también creo que esto también es estúpido porque PropertyChangingEventArgs no hereda CancelEventArgs, ya que cancelar con una excepción no siempre es la solución elegante, además, arrojar excepciones cuesta más rendimiento que llamar al OnPropertyChangingEvent y luego verificar el e.Cancelado devuelto , por lo tanto, cuesta menos que elevar el PropertyChangingEvent, que de todos modos los llamas a ambos.
También se puede lanzar una excepción en el controlador de todos modos en lugar de marcar e.Cancel como verdadero, para aquellos que insisten en seguir el camino de Excepción. Vote aquí .
Para responder quizás parte de su pregunta o exponer la respuesta de ADB, puede usar ObjectStateManager.GetObjectStateEntry para buscar el estado de las entidades y escribir su lógica predeterminada personalizada.
SaveChanges es el método en el contexto que puede usar, o SavingChanges es el evento que ocurre antes de que se llame a SaveChanges.
Puede anular SaveChanges y solo llamar a base.SaveChanges si no desea cancelar el cambio
También hay un evento ObjectMaterialized para el contexto.
Entre los dos puede pegar todo su código de validación y creación en una ubicación, que puede ser apropiada si son complejas e incluyen valores de otros objetos, etc.
Esto es en respuesta a un comentario que dejé. Espero que esto responda a tu pregunta, Shimmy. Solo comente, y lo acortaré o eliminaré si no responde su pregunta.
Necesitará ambas interfaces INotifyPropertyChanging e INotifyPropertyChanged para ser implementadas en su clase (a menos que sea algo así como un objeto de entidad de marco, que creo que implementa estos internamente).
Y antes de establecer un valor para esta propiedad, deberá elevar el evento NotifyPropertyChanging.PropertyChanging, utilizando el nombre de la propiedad en el constructor PropertyChangingEventArgs.
Y después de establecer este valor, debe elevar el evento NofityPropertyChanged.PropertyChanged, de nuevo usando el nombre de la propiedad que se está generando en el constructor PropertyChangedEventArgs.
Luego debe manejar los eventos PropertyChanging y PropertyChanged. En el evento PropertyChanging, debe almacenar en caché el valor. En el evento PropertyChanged, puede comparar y lanzar una excepción.
Para obtener la propiedad de argumentos de eventos PropertyChanging / PropertyChanged, debe usar la relización.
// 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
Observe cómo estoy usando PreventRecursion, que es un booleano que olvidé agregar sobre estos métodos? Cuando restablece la propiedad a su valor anterior, estos eventos serán recuperados.
tl; dr
Ahora podría derivar un único evento que hereda de INotifyPropertyChanged, pero utiliza un argumento que contiene un objeto que representa el valor anterior, así como el nombre de la propiedad. Y eso reduciría la cantidad de eventos activados a uno, tiene una funcionalidad similar y tiene compatibilidad con INotifyPropertyChanged.
Pero si desea manejar algo antes de que se establezca la propiedad (digamos que la propiedad realiza un cambio irreversible o necesita configurar otras propiedades antes de configurar esa variable, de lo contrario se lanzará una excepción) no podrá hacer eso.
En general, este método es una forma muy antigua de hacer las cosas. Tomaría la respuesta de Poker Villian y podría ingresar datos inválidos. Pero no permite guardar en una base de datos.
Entity Framework tiene un código excelente para la validación. Usted agrega validación a sus propiedades a través de atributos. Y luego se encarga del trabajo de procesar esos atributos. Luego puede crear una propiedad llamada IsValid, que llama a la validación específica de Entity Framework. También distingue los errores de campo (como escribir los caracteres incorrectos o tener una cadena demasiado larga) y los errores de clase (como tener datos faltantes o claves conflictivas).
Luego puede vincular IsValid a la validación de los controles, y mostrarán una burbuja roja mientras se ingresan datos no válidos. O simplemente podría implementar la validación de IsValid usted mismo. Pero si IsValid es falso, el evento SaveChanges necesitaría cancelar el guardado.
por cierto. El código proporcionado no se compilará y solo es un pseudocódigo (mezclando vb y c #). Pero creo que es mucho más descriptivo que c # solo, mostrando exactamente lo que se está manejando.