Domanda

ha esperienza a qualcuno il seguente? Convalida oggetti con i campi che fanno riferimento ad altri soggetti sarebbe buttare un errore che indica che il campo non era presente e che, quando si eseguire il debug del programma e si dovrebbe controllare le entità che i campi popolato.

Questo è successo a me in due occasioni e sembra essere un qualche problema con caricamento pigro, come se il lazy loading non ha dato una risposta abbastanza veloce.

Abbiamo questo modello (semplificato) dove

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

Se vogliamo solo fare Context.Surveys.Single(id) o Context.Surveys.Where(s => s.Id == id), modificando il campo Enabled (o qualsiasi altro campo), e fare un Context.SaveChanges() sarebbe in 9 volte su 10 gettano un errore di convalida che il campo OU è richiesto e che non è presente .

Dopo aver aggiunto .Include(s => s.OU) questo problema è stato risolto e ho pensato che questa fosse la fine di esso. Anche se ieri ancora una volta ho incontrato un problema simile con il seguente codice:

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));
        }
    }
}

Questa sarebbe tornato ValidationErrors per i valori di [4,5], mentre Questions al momento dell'ispezione attraverso il debugger domande davvero contenuti con Ids 4 e 5. Se avrei mettere in pausa il debugger un momento sulla if-dichiarazione la convalida sarebbe passare attraverso correttamente in seguito .

La cosa strana è che non ho (consapevolmente) verificano questi errori prima e che non ho aggiornato le librerie o software di database.

Questa situazione mi spaventa un po 'come sembra che non posso contare su Lazy Loading per sempre il lavoro. O forse sto facendo qualcosa di sbagliato?

Questo si sente stretta relazione con le EF 4.1 carico filtrato collezioni bambino non funziona per molti-a-molti ma non riesco a spiegare come questo si applicherebbe qui.

Update1 : Il seguente eccezione sarebbe popup seguendo le istruzioni fornite nel primo esempio:

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>

Il codice per ottenere questo (non scritto da me personalmente, ma un altro team-member):

        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 è un oggetto che contiene i post-dati dal client. survey.CanAdministrate(Context) utilizza il contesto per leggere l'intero albero di OrganisationalUnits dal DB per determinare ruoli.

È stato utile?

Soluzione

This is by design and IMHO it is very good feature. Context internally turns off lazy loading in some operations and validation is one of them. This is part of internal implementation of the method which causes it:

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;
}

Why is it good? Because it avoids leaky lazy loads in case when you don't want them. Btw. if you placed validation logic on property which doesn't have to be loaded you did it wrong. It is your responsibility to ensure that all necessary properties are filled prior to validation.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top