当调用实体的IValidatableObject.Validate方法时,EF6代理的引用有时为null

时间:2015-05-15 20:58:38

标签: entity-framework entity-framework-6 nullreferenceexception

当我的实体的IValidatableObject.Validate方法被DbContext的SaveChangesAsync方法调用时,EF6代理的引用有时为null。

多次运行相同的确切代码会导致不同的行为。如果我在Sku方法之外检查我的股票的stock.Sku == null属性(即Validate),它将始终返回实体化实体。如果我不这样做并且仅在this.Sku方法中检查Validate,那么this.Sku 有时对于完全相同的实体而言为空。并且通过“完全相同的实体”,我的意思是我在所有测试运行中多次测试具有相同IdSkuId的一个库存。我不是在这里创建新股票或更改其SkuId属性的值。我正在做的一件事是调用股票的ChangeQuantity方法,然后保存更改。

我最好的猜测是,一旦保存更改被调用,所有实体和参考实现都将被冻结。如果Sku属性至少没有被访问过一次,那么当数据库上下文的保存更改代码调用我的对象的Validate方法时,它将为null并保持为空。

我的问题是:为什么会发生这种情况?为什么我不能依赖于可以随时延迟加载的属性?

public abstract class StockBase : RecordBase
{
    // Snipped //

    [Required, Display(Name = "SKU")]
    public Guid SkuId { get; set; }
    [Display(Name = "SKU")]
    public virtual Sku Sku { get; protected set; }

    [Required]
    public int Quantity { get; private set; }

    [DataType("StockActions")]
    public virtual ICollection<StockAction> Actions { get; private set; }

    public void ChangeQuantity(DateTime logged, Guid loggedById, int changeInQuantity, string notes = null)
    {
        TrackChange(logged, loggedById);
        Quantity += changeInQuantity;
        Actions.Add(new StockAction(logged, loggedById, changeInQuantity));
    }
}

public class StandardStock : StockBase, IValidatableObject
{
    // Snipped //

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        // Right here is where `this.Sku` is sometimes null!
        if (Sku.IsExpiringStock)
        {
            throw new InvalidOperationException("Standard stock must have a non-expiring SKU.");
        }

        yield break;
    }
}

2 个答案:

答案 0 :(得分:1)

不幸的是,在通过Entity Framework执行验证期间,延迟加载被禁用。

https://msdn.microsoft.com/en-us/data/gg193959#Considerations

答案 1 :(得分:0)

看起来您正在使用延迟加载来填充Sku对象。手动测试Sku属性时,您正在强制运行延迟加载,并且值已实现。如果您在期望加载上下文时已经对上下文执行了某些操作,或者已经处理了上下文,那么它将保持为空。

如果您始终需要填充此属性,请考虑在加载实体时显式加载它。这将停止您的延迟加载问题,并且还可以消除数据库之旅。