Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to validate models before SaveChanges in EntityFramework Core 2?

I want to validate the graph of objects (from different but related entities) being saved with Entity Framework Core. In Entity Framework 6, the framework validates it at SaveChanges Operation. In EF Core, the docs says the validation is not performed automatically. So, in ASP MVC Core, we can use the ModelState.IsValid. But, i'm not using ASP MVC and i prefer to not depend on that very big framework.

Anyway, How I can validate models before SaveChanges in EntityFramework Core 2, without depending on full ASP MVC framework?

like image 687
gabomgp Avatar asked Aug 19 '17 18:08

gabomgp


People also ask

How do I validate a model in Entity Framework?

Entity Framework provides a great variety of validation features that can feed through to a user interface for client-side validation or be used for server-side validation. When using code first, you can specify validations using annotation or fluent API configurations.

What does the DbContext SaveChanges () method return?

What does the DbContext SaveChanges () method return? Returns. The number of state entries written to the underlying database. This can include state entries for entities and/or relationships.

How do I use SaveChanges in Entity Framework?

In Entity Framework, the SaveChanges() method internally creates a transaction and wraps all INSERT, UPDATE and DELETE operations under it. Multiple SaveChanges() calls, create separate transactions, perform CRUD operations and then commit each transaction. The following example demonstrates this.


1 Answers

Yeah, looks like there is no out of the box validation. You can handle it by yourself by overriding SaveChanges:

public class MyContext : DbContext
{
    public virtual DbSet<Model> Models { get; set; }

    public MyContext()
    {
    }

    public override int SaveChanges()
    {
        var changedEntities = ChangeTracker
            .Entries()
            .Where(_ => _.State == EntityState.Added || 
                        _.State == EntityState.Modified);

        var errors = new List<ValidationResult>(); // all errors are here
        foreach (var e in changedEntities)
        {
            var vc = new ValidationContext(e.Entity, null, null);
            Validator.TryValidateObject(
                e.Entity, vc, errors, validateAllProperties: true);
        }

        return base.SaveChanges();
    }
}

public class Model
{
    [Key]
    public int Id { get; set; }

    [Required]
    [MaxLength(32)]
    public string Field { get; set; }

    [Range(15, 25)]
    public int RangeField { get; set; }
}
  • Property validateAllProperties is important because without it you won't get range validations.
  • Don't forget to override SaveChangesAsync.

This thing won't be really helpful if you set constraints with fluent syntax, unfortunately. Actually, as fluent syntax can possibly not only add new constraints, but also override existing, it's better to switch completely to attributes annotation, or find another way to make validation.

like image 77
cassandrad Avatar answered Sep 30 '22 06:09

cassandrad