2008-11-19 27 views
13

Soy consciente de que hay un evento AssociationChanged, sin embargo, este evento se desencadena 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?Validación y uso de Entity Framework

Además, me gustaría establecer valores predeterminados para mi entidad basados ​​en la información de otras entidades , pero hago esto solo cuando sé que la entidad está instanciada 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 considérada la que debería estar fuera de la lógica empresarial de mi entidad?

Si ese es el caso, ¿entonces debería estar diseñando 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 adaptador EFPoco 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?

Respuesta

0

En cuanto a su primera pregunta, simplemente implementaría los cambios a las asociaciones como lógica de negocios. Por ejemplo, si se agrega una clase del profesor con el estudiante múltiple, no añada por los estudiantes como

aTeacher.Students.Add(new Student) 

lugar, crear 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; 
} 

esa manera usted tiene el control total sobre cuando se cambian 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.

En relación con la segunda parte de su pregunta, probablemente podría utilizar 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 utilizar para determinar qué objetos son nuevos y establecer algunos valores.

Pero quizás 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 la base de datos.

Buena suerte

0

Crear una fábrica que produce instancias para usted dependiendo de 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); 
} 
0

Es una falta grave no tener un AssociationChanging (que hereda de CancelEventArgs) evento.

Me molesta también en gran medida, por lo tanto, me informó de esto a Microsoft Connect Please vote here!

Y por cierto, también creo que esto también es estúpida que los PropertyChangingEventArgs no hereda CancelEventArgs, desde que se canceló con una excepción es No siempre la solución elegante, además, arrojar excepciones cuesta más rendimiento que llamar al OnPropertyChangingEvent y luego verificar el e.Cancel devuelto, por lo que cuesta menos que elevar el PropertyChangingEvent, que de todas maneras los llamas a ambos.
también una excepción puede ser lanzado en el controlador de todos modos en lugar de marcar e.Cancel tan cierto, para aquellos que insisten en ir por el camino de excepción. Vote Here.

+1

PropertyChangingEventArgs no tiene ninguna relación con CancelEventArgs. Tienen tiempos que necesitan ser utilizados exclusivamente para diferentes propósitos. Forzar la herencia causaría complicación y frustración innecesarias (unirlas estrechamente). Hay PropertyChangingEvent y PropertyChangedEvent, y creo que satisfacen la funcionalidad que usted desea sin que se le hagan cambios (sin mencionar que rompería la compatibilidad de .NET 1.1 con .NET 4.0). – TamusJRoyce

+0

@TamusJRoyce, OK, estoy de acuerdo, no debería heredar de 'CancelEventArgs', pero lo que debería hacer es mi otra solicitud que proporciona el valor candidato (que la manera más fácil de conseguirlo es obtener los atributos de método actuales con un significado significativo cantidad de costo de rendimiento). – Shimmy

0

Para responder a tal parte de su pregunta o exponer sobre la respuesta de ADB que pueda usuario ObjectStateManager.GetObjectStateEntry para encontrar el estado de las entidades y escribir la lógica de defecto personalizada.

SaveChanges es el método en el contexto que se puede utilizar, o SavingChanges es el evento que se produce antes SaveChanges se llama.

Puede anular SaveChanges y base.SaveChanges única llamada Si no desea abortar el cambio

También hay un evento ObjectMaterialized para el contexto.

Entre los dos puede pegarse toda su validación y código de creación en un solo lugar, lo que puede ser apropiado si son complejas e incluyen valores de otros objetos, etc ..

2

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á las 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 subir el evento NofityPropertyChanged.PropertyChanged, nuevamente utilizando el nombre de la propiedad que se está generando en el constructor PropertyChangedEventArgs.

entonces usted tiene que controlar 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 del evento args PropertyChanging/PropertyChanged, es necesario utilizar 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 

Observe cómo estoy usando PreventRecursion, que es un valor lógico me olvidó añadir por encima de estos métodos? Cuando restablece la propiedad a su valor anterior, estos eventos serán recuperados.

tl; dr

Ahora se podría derivar un solo evento que hereda de INotifyPropertyChanged, pero utiliza un argumento que sostiene 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 quiere manejar algo antes de que se establezca la propiedad (digamos que la propiedad hace un cambio irreversible o necesita configurar otras propiedades antes de establecer esa variable, de lo contrario se lanzará una excepción) no podrá Haz 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).

A continuación, puede vincular IsValid a la validación de controles, y se mostrará 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.

btw. 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.