Lazy / aufgeschobener Laden von Links nicht pünktlich?
-
25-10-2019 - |
Frage
Hat jemand Folgendes erlebt? Validierung von Objekten mit Feldern, die sich auf andere Entitäten beziehen sind besiedelt.
Das ist mir jetzt zweimal passiert und es scheint ein Problem mit faulen Laden zu sein, als ob das faule Laden die Antwort nicht schnell genug gegeben hätte.
Wir haben dieses (vereinfachte) Modell wo
class Survey {
...
public bool Enabled {get; set;}
[Required]
public virtual OrganisationalUnit OU {get; set;}
...
}
Wenn wir einfach tun würden Context.Surveys.Single(id)
oder Context.Surveys.Where(s => s.Id == id)
, wechseln Enabled
Feld (oder ein anderes Feld) und machen a Context.SaveChanges()
Es würde in 9 von 10 mal einen Validierungsfehler werfen, dass die OU
Feld ist erforderlich und es ist nicht vorhanden.
Nach dem Hinzufügen .Include(s => s.OU)
Dieses Problem wurde gelöst und ich dachte, dies sei das Ende. Obwohl gestern wieder ein ähnliches Problem mit dem folgenden Code gestoßen bin:
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));
}
}
}
Dies würde ValidationErrors für Werte [4,5] während der Rückgabe Questions
Bei der Inspektion durch den Debugger enthielt tatsächlich Fragen mit Id
S 4 und 5. Wenn ich den Debugger einen Moment auf dem Pause machen würde if
-datement Die Validierung würde danach korrekt durchlaufen.
Das Seltsame ist, dass ich diese Fehler zuvor (wissentlich) nicht erlebt habe und dass ich keine Bibliotheken oder Datenbanksoftware aktualisiert habe.
Diese Situation erschreckt mich ein wenig, da ich mich nicht darauf verlassen kann, dass ich immer wieder arbeitet. Oder mache ich etwas falsch?
Dies fühlt sich lose zu tun mit EF 4.1 Ladefilterte Kindersammlungen funktionieren nicht für viele zu viele zu viele Aber ich kann nicht erklären, wie dies hier zutreffen würde.
Update1: Die folgende Ausnahme würde nach den im ersten Beispiel angegebenen Schritten folgen:
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>
Der Code, um dies zu erreichen (nicht persönlich, sondern ein weiteres Team-Mitglied):
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
ist ein Objekt, das die Post-Data vom Client enthält. survey.CanAdministrate(Context)
Verwendet den Kontext, um den gesamten Baum der Organisationsinits aus der DB zu lesen, um die Rollen zu bestimmen.
Lösung
Dies ist von Design und IMHO sehr gut. Der Kontext schaltet sich intern in einigen Operationen aus, und die Validierung ist einer davon. Dies ist Teil der internen Implementierung der Methode, die sie verursacht:
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;
}
Warum ist es gut? Denn es vermeidet undichte faule Lasten für den Fall, wenn Sie sie nicht wollen. Übrigens. Wenn Sie die Validierungslogik für Eigenschaften platziert haben, die nicht geladen werden müssen, haben Sie es falsch gemacht. Es liegt in Ihrer Verantwortung, sicherzustellen, dass alle erforderlichen Eigenschaften vor der Validierung gefüllt werden.