0

IValidatableObject.Validate 仅在实现实体 DbEntityEntry.State 不同于“未更改”时才被调用。并且仅更改导航属性不会更改状态,因此永远不会发生验证。

为什么微软总是发布半生不熟的测试版?

我什至无法手动检测导航属性的变化:

var changes = context.ChangeTracker.Entries()
    .Where(e => e.State != EntityState.Unchanged)
    .ToArray();

返回一个空数组。

4

1 回答 1

5

这里有几个有趣的点。EntityFramework 独立于实体的更改跟踪导航属性的更改。context.ChangeTracker.Entries() 仅返回对实体的更改,而不是对关系的更改。这就是你看不到这些的原因。如果您真的想查看关系以及它们如何变化,您可以下拉到 ObjectContext 并执行以下操作:

var objectContext = ((IObjectContextAdapter) ctx).ObjectContext;
foreach(var relationshipEntry in objectContext.ObjectStateManager
                                              .GetObjectStateEntries(EntityState.Added | EntityState.Modified | EntityState.Deleted)
                                              .Where(e => e.IsRelationship))
{
    EntityKey entityKey1, entityKey2;

    if (relationshipEntry.State == EntityState.Added)
    {
        entityKey1 = (EntityKey)relationshipEntry.CurrentValues[0];
        entityKey2 = (EntityKey)relationshipEntry.CurrentValues[1];            
    }
    else
    {
        entityKey1 = (EntityKey)relationshipEntry.OriginalValues[0];
        entityKey2 = (EntityKey)relationshipEntry.OriginalValues[1];                        
    }

    var entity1 = objectContext.GetObjectByKey((EntityKey)entityKey1);
    var entity2 = objectContext.GetObjectByKey((EntityKey)entityKey2);
}

对我来说更有趣的场景是当关系发生变化时需要重新验证实体的场景。我假设您没有外键 - 否则您的实体将被标记为已修改,因为更改导航属性会更改外键的值,这反过来会将实体标记为已修改。无论如何,鉴于我有三个有效实体 - 改变关系可能使实体(或模型)无效的情况是什么?另外,请注意,验证本身仅验证给定实体,但从不遵循导航属性来验证相关实体。最后,如果您真的需要在关系发生变化时验证实体,我认为您有 4 个选项:

  • 尝试添加外键,以便更改关系将更改应将实体标记为已修改的外键(免责声明:我没有尝试过)

  • 覆盖 DbContext.ShouldValidateEntity() 方法以验证所有实体,而不是仅验证修改的实体(这是过滤逻辑发生的地方)。请注意,它可能会对性能产生一些负面影响。这是您需要添加到从 DbContext 派生的类的代码:

        protected  override bool ShouldValidateEntity(DbEntityEntry entityEntry)
        {
            return (entityEntry.State & EntityState.Deleted) == 0;
        }
  • 覆盖 DbContext.SaveChanges() 以便您为所有修改的实体和涉及修改的关系的所有实体调用验证(使用上面的代码,您很可能只对已添加的关系条目感兴趣)

  • 当您修改集合时,手动将实体标记为已修改。请注意,它可能会导致向数据库发送不需要的更新,因此取决于您跟踪的实体数量,仅验证所有未删除的实体可能会便宜得多

您可以在此处找到有关验证和验证自定义的更多详细信息: http: //blogs.msdn.com/b/adonet/archive/2010/12/15/ef-feature-ctp5-validation.aspx http://blogs.msdn .com/b/adonet/archive/2011/05/27/ef-4-1-validation.aspx(是的,它适用于 CTP 和 EF 4.1,但仍然有效)

于 2012-04-24T18:58:36.800 回答