问题
IValidatableObject.Validate only gets called when the implementing entities DbEntityEntry.State differs from "Unchanged". And just changing a navigation property won't change the state and so the validation will never occur.
Why Microsoft always releases half-baked beta things?
I cannot even detect the navigation property change by hand:
var changes = context.ChangeTracker.Entries()
.Where(e => e.State != EntityState.Unchanged)
.ToArray();
Returns an empty array.
回答1:
There are a few interesting points here. EntityFramework tracks changes to navigation properties independently on the changes to entities. context.ChangeTracker.Entries() returns only changes to entities and not to relationships. This is the reason why you don't see these. If you really want to look at relationships and how they changed you can drop down to the ObjectContext and do the following:
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);
}
The scenario that is more interesting to me is the one when you need to re-validate your entity when the relationship changes. I assume that you don't have foreign keys - otherwise your entity would have been marked as modified as changing the navigation proprerty would change the value of the foreign key which in turn would mark the entity as modified. Anyways given that I have three valid entities - what is the scenario where changing relationships could make the entity (or the model) invalid? Also, note that validation by itself is only validating the given entity but never follows navigation properties to validate related entities. Finally if you really need to validate entities when relationships change I think you have 4 options:
try adding foreign keys so that changing relationships will change the foreign key which should mark the entity as modified (disclaimer: I have not tried that)
override DbContext.ShouldValidateEntity() method to validate all the entities instead of only modified ones (this is where the filtering logic happens). Note that it may have some negative impact on performance. Here is the code you would need to add to your class derived from DbContext:
protected override bool ShouldValidateEntity(DbEntityEntry entityEntry)
{
return (entityEntry.State & EntityState.Deleted) == 0;
}
override DbContext.SaveChanges() so that you invoke validation for all modified entities and for all entities that are involved in modified relationships (use the code above, you are most likely only interested in relationship entries that have been added)
when you modify a collection manually mark the entity as modified. Note that it may cause sending unneeded updates to the database so depending on how many entities you are tracking it may be much cheaper just to validate all but deleted entities
You can find more details about validation and validation customization here: 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 (Yes it's for the CTP and EF 4.1 but it sill holds)
来源:https://stackoverflow.com/questions/10300156/ivalidatableobject-is-useless-for-ef-navigation-properties