Pregunta

¿Alguien experimentó lo siguiente? Validar objetos con campos que se refieren a otras entidades le enviarían un error que indica que el campo no estaba presente y que cuando depuraría el programa e inspeccionaría las entidades que los campos son poblado.

Esto me ha sucedido en dos ocasiones ahora y parece ser algún problema con la carga perezosa, como si la carga perezosa no diera la respuesta lo suficientemente rápido.

Tenemos este modelo (simplificado) donde

class Survey {
  ...
  public bool Enabled {get; set;}
  [Required]
  public virtual OrganisationalUnit OU {get; set;}
  ...
}

Si lo hiciéramos Context.Surveys.Single(id) o Context.Surveys.Where(s => s.Id == id), cambiando el Enabled campo (o cualquier otro campo) y hacer un Context.SaveChanges() En 9 de 10 veces lanzaría un error de validación que el OU Se requiere campo y que no está presente.

Después de agregar .Include(s => s.OU) Este problema se resolvió y pensé que este era el final. Aunque ayer nuevamente encontré un problema similar con el siguiente código:

public class SurveyQuestionMultipleChoiceMultiSelect : SurveyQuestionMultipleChoice
{
    public override IEnumerable<ValidationResult> validateValue(string _, IEnumerable<string> values)
    {
        int ivalue;
        foreach( string value in values) {

            bool success = int.TryParse(value, out ivalue);

            if (!success || !Questions.Any(q => q.Id == ivalue))
                yield return new ValidationResult(String.Format(GUI.error_multiplechoice_answer_not_element_of, ivalue));
        }
    }
}

Esto devolvería la validación para los valores [4,5] mientras Questions Tras la inspección a través del depurador, de hecho contenía preguntas con Ids 4 y 5. Si pausaría al depurador un momento en el if-Encatación La validación pasaría correctamente después.

Lo extraño es que no experimenté (a sabiendas) estos errores antes y que no actualicé ninguna biblioteca o software de base de datos.

Esta situación me asusta un poco, ya que parece que no puedo confiar en la carga perezosa para que siempre funcione. ¿O tal vez estoy haciendo algo mal?

Esto se siente libremente relacionado con EF 4.1 Carga de colecciones de niños filtrados no funcionan para muchos a muchos Pero no puedo explicar cómo se aplicaría esto aquí.

Actualización1: La siguiente excepción aparecería siguiendo los pasos proporcionados en el primer ejemplo:

System.Data.Entity.Validation.DbEntityValidationException was unhandled by user code
  Message=Validation failed for one or more entities. See 'EntityValidationErrors' property for more details.
  Source=EntityFramework
  StackTrace:
       at System.Data.Entity.Internal.InternalContext.SaveChanges()
       at System.Data.Entity.Internal.LazyInternalContext.SaveChanges()
       at System.Data.Entity.DbContext.SaveChanges()
       at Caracal.Application.Controllers.SurveyController.BulkEnable(SurveyBulkAction data) in C:\Users\Alessandro\Caracal\DigEvalProject\trunk\Caracal\application\Controllers\SurveyController.cs:line 353
       at lambda_method(Closure , ControllerBase , Object[] )
       at System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters)
       at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters)
       at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
       at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClass15.<InvokeActionMethodWithFilters>b__12()
       at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation)
  InnerException: 
    <really-empty>

El código para lograr esto (no escrito por mí personalmente, sino otro miembro del equipo):

        bool option = data.option == "true";

        // Check if all surveys can be set to the enabled state
        foreach (int id in data.surveys)
        {
            Survey survey = Context.Surveys.SingleOrDefault(s => s.Id == id);
            if (survey == null || !survey.CanAdministrate(Context))
                return JsonResponse.Error(GUI.survey_enable_change_bulk_failed);

            surveys.Add(survey);
        }

        // Enable/disable the selected surveys.
        foreach (Survey survey in surveys)
            survey.Enabled = option;

        Context.SaveChanges();

data es un objeto que contiene los datos postales del cliente. survey.CanAdministrate(Context) Utiliza el contexto para leer todo el árbol de las unidades de organización de la DB para determinar los roles.

¿Fue útil?

Solución

Esto es por diseño y en mi humilde opinión es una muy buena característica. El contexto apaga internamente la carga perezosa en algunas operaciones y la validación es una de ellas. Esto es parte de la implementación interna del método que lo causa:

public virtual DbEntityValidationResult GetValidationResult(IDictionary<object, object> items)
{
    EntityValidator entityValidator = 
        this.InternalContext.ValidationProvider.GetEntityValidator(this);
    bool lazyLoadingEnabled = this.InternalContext.LazyLoadingEnabled;
    this.InternalContext.LazyLoadingEnabled = false;
    DbEntityValidationResult result = null;
    try
    {
        ...
    }
    finally
    {
        this.InternalContext.LazyLoadingEnabled = lazyLoadingEnabled;
    }
    return result;
}

¿Por qué es bueno? Porque evita cargas perezosas con fugas en caso de que no las quieras. Por cierto. Si colocó la lógica de validación en la propiedad que no tiene que cargarse, lo hizo mal. Es su responsabilidad asegurarse de que todas las propiedades necesarias se llenen antes de la validación.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top