延迟/延迟加载链接不及时? [英] Lazy / Deferred loading of links not on time?

查看:104
本文介绍了延迟/延迟加载链接不及时?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有人遇到以下情况吗?使用引用其他实体的字段来验证对象会给您一个错误,指出该字段不存在,并且当您调试该程序时,您将检查填充 的实体。 / p>

现在我已经发生了两次,似乎是延迟加载的一些问题,好像延迟加载没有给出足够的答案。 >

我们有这个(简化的)模型,其中

  class Survey {
...
public bool启用{get; set;}
[必需]
public virtual OrganisationalUnit OU {get; set;}
...
}

如果我们只是做 Context.Surveys.Single(id) Context.Surveys.Where(s => s.Id == id),更改启用字段(或任何其他字段),并执行 Context.SaveChanges() 9分10分之内抛出一个确认错误,表示 OU 字段是必需的,并且它不存在。



之后添加 .Include(s => s.OU)这个问题已经解决了,我以为这是结束了。虽然昨天我再次遇到类似的问题:

  public class SurveyQuestionMultipleChoiceMultiSelect:SurveyQuestionMultipleChoice 
{
public override IEnumerable< ValidationResult> validateValue(string _,IEnumerable< string> values)
{
int ivalue;
foreach(值中的字符串值){

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

if(!success ||!Questions.Any(q => q.Id == ivalue))
yield返回新的ValidationResult(String.Format(GUI.error_multiplechoice_answer_not_element_of,ivalue) );
}
}
}

这将返回ValidationErrors的值[4,5]而问题在通过调试器检查确实包含问题与 Id s 4和5.如果我如果 -statement,验证将会正确执行,那么将会在上暂停调试器。



奇怪的是是,我没有(故意)以前遇到这些错误,我没有更新任何图书馆或数据库软件。



这种情况吓到我有点像似乎我不能依赖于Lazy Loading一直工作。或者也许我在做错事?



感觉与 EF 4.1加载过滤的儿童集合不适用于多对多的,但我无法解释如何



Update1
按照第一个示例中提供的步骤,弹出以下异常: p>

  System.Data.Entity.Validation.DbEntityValidationException被用户代码未处理
Message =一个或多个实体的验证失败。有关详细信息,请参阅EntityValidationErrors属性。
Source = EntityFramework
StackTrace:
在System.Data.Entity.Internal.InternalContext.SaveChanges()
在System.Data.Entity.Internal.LazyInternalContext.SaveChanges()
在System.Data.Entity.DbContext.SaveChanges()
在Caracal.Application.Controllers.SurveyController.BulkEnable(SurveyBulkAction数据)在C:\Users\Alessandro\Caracal\DigEvalProject\ trunk \Caracal\application\Controlers\SurveyController.cs:line 353
at lambda_method(Closure,ControllerBase,Object [])
在System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase控制器,Object []参数)
在System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext,IDictionary`2参数)
在System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext,ActionDescriptor actionDescriptor, IDictionary`2参数)
a在System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter过滤器,ActionExecutingContext preContext,Func`1连续)中,$ b $12()
$ System.Web.Mvc.ControllerActionInvoker。c__DisplayClass15。&$ InvokeActionMethodWithFilters& $ b InnerException:
< really-empty>

实现这个的代码(不是我个人写的,而是另一个团队成员): p>

  bool option = data.option ==true; 

//检查所有调查是否可以设置为启用状态
foreach(data.surveys中的int id)
{
调查Survey = Context.Surveys。 SingleOrDefault(s => s.Id == id);
if(survey == null ||!survey.CanAdministrate(Context))
return JsonResponse.Error(GUI.survey_enable_change_bulk_failed);

survey.Add(survey);
}

//启用/禁用所选调查。
foreach(调查调查调查)
survey.Enabled = option;

Context.SaveChanges();

数据来自客户端的数据 survey.CanAdministrate(Context)使用Context从DB读取OrganisationalUnits的整个树,以确定角色。

解决方案

这是通过设计和IMHO这是非常好的功能。内部关闭在一些操作中的延迟加载,并且验证是其中之一。这是引起它的方法的内部实现的一部分:

  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;
}
返回结果;
}

为什么好?因为它避免了泄漏的惰性负载,以防您不想要它们。顺便说一句。如果您将验证逻辑放在不需要加载的属性上,那么您的错误。您有责任确保在验证之前填写所有必需的属性。


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

解决方案

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.

这篇关于延迟/延迟加载链接不及时?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆