Efcore: IValidatableObject

Created on 6 Nov 2015  路  4Comments  路  Source: dotnet/efcore

Does EF7 still automatically validate IValidatableObject entities upon saving?
I'm not seeing any of my IValidatableObject.Validate() methods getting called. Is there something I need to configure now?

Most helpful comment

@joshmouch if you take MVC as the most extreme example, validation happens on the client, then again in the action to protect against malicious requests. Most validation also happen in the database too (nullability of columns, max length of data, etc.). Obviously not all apps go that far, but validating during SaveChanges is usually just front loading an exception you would get from the database and adding overhead to do that.

BTW if you do want to validate IValidatableObject during SaveChanges then it's one fairly simple line of code to find the validation errors, I've included a code listing below that shows an example...

``` c#
public class BloggingContext : DbContext
{
public DbSet Blogs { get; set; }

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFGetStarted.ConsoleApp;Trusted_Connection=True;");
}

public override int SaveChanges()
{
    var validationErrors = ChangeTracker
        .Entries<IValidatableObject>()
        .SelectMany(e => e.Entity.Validate(null))
        .Where(r => r != ValidationResult.Success);

    if(validationErrors.Any())
    {
        // Whatever you want to do on an error
    }

    return base.SaveChanges();
}

}

public class Blog : IValidatableObject
{
public int BlogId { get; set; }
public string Url { get; set; }

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
    if (Url.StartsWith("http://"))
    {
        yield return ValidationResult.Success;
    }
    else
    {
        yield return new ValidationResult("Url must start with 'http://'");
    }
}

}
```

All 4 comments

EF7 does not do any of this type of validation. You could easily override SaveChanges if you want to do it, but typically the validation is already done by the app and then re-checked by the database, so we opted not to do it automatically in EF7.

That's a shame. Checking twice seems like a good thing to me. In what cases is validation of entities already done in the app? I can only see that happening if: a) entity objects are being used as view models, b) you have a well developed business layer between UI and DB layers. Otherwise, the average developer is probably validating the view model before validating the entity, not validating the entity twice. Correct?

@joshmouch if you take MVC as the most extreme example, validation happens on the client, then again in the action to protect against malicious requests. Most validation also happen in the database too (nullability of columns, max length of data, etc.). Obviously not all apps go that far, but validating during SaveChanges is usually just front loading an exception you would get from the database and adding overhead to do that.

BTW if you do want to validate IValidatableObject during SaveChanges then it's one fairly simple line of code to find the validation errors, I've included a code listing below that shows an example...

``` c#
public class BloggingContext : DbContext
{
public DbSet Blogs { get; set; }

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFGetStarted.ConsoleApp;Trusted_Connection=True;");
}

public override int SaveChanges()
{
    var validationErrors = ChangeTracker
        .Entries<IValidatableObject>()
        .SelectMany(e => e.Entity.Validate(null))
        .Where(r => r != ValidationResult.Success);

    if(validationErrors.Any())
    {
        // Whatever you want to do on an error
    }

    return base.SaveChanges();
}

}

public class Blog : IValidatableObject
{
public int BlogId { get; set; }
public string Url { get; set; }

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
    if (Url.StartsWith("http://"))
    {
        yield return ValidationResult.Success;
    }
    else
    {
        yield return new ValidationResult("Url must start with 'http://'");
    }
}

}
```

@rowanmiller thanks for that example.

Was this page helpful?
0 / 5 - 0 ratings