Did someone experience the following? Validating objects with fields that refer to other Entities would throw you an error stating that the field wasn't present and that when you would debug the program and you would inspect the entities that the fields are populated.
This has happened to me on two occasions now and it seems to be some problem with lazy loading, as if the lazy loading did not give the answer fast enough.
We have this (simplified) model where
class Survey {
...
public bool Enabled {get; set;}
[Required]
public virtual OrganisationalUnit OU {get; set;}
...
}
If we would just do Context.Surveys.Single(id)
or Context.Surveys.Where(s => s.Id == id)
, changing the Enabled
field (or any other field), and do a Context.SaveChanges()
it would in 9 out of 10 times throw a validation error that the OU
field is required and that it's not present.
After adding .Include(s => s.OU)
this problem was solved and I thought this was the end of it. Although yesterday again I encountered a similar problem with the following code:
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));
}
}
}
This would return ValidationErrors for values [4,5] whilst Questions
upon inspection through the debugger indeed contained questions with Id
s 4 and 5. If I would pause the debugger a moment on the if
-statement the validation would go through correctly afterwards.
The odd thing is that I didn't (knowingly) experience these errors before and that I didn't update any libraries or database software.
This situation frightens me a bit as it seems I cannot rely on Lazy Loading to always work. Or maybe I'm doing something wrong?
This feels loosely related to EF 4.1 loading filtered child collections not working for many-to-many but I cannot explain how this would apply here.
Update1: The following exception would popup by following the steps provided in the first example:
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>
The code to achieve this (not written by me personally, but another 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
is an object containing the post-data from the client. survey.CanAdministrate(Context)
uses the Context to read the whole tree of OrganisationalUnits from the DB to determine roles.