0

Background
With ef core code first approach, validation is robust and simple: https://learn.microsoft.com/en-us/aspnet/core/tutorials/first-mvc-app/validation

With the database first approach, it seems like any validation is happening behind the scenes by the database when dbcontext.SaveChanges(); is called. What's worse, these exceptions are nebulous and entirely unhelpful, for example, SqlException: String or binary data would be truncated can be thrown if any of the string properties of any of the entities have too many chars (ours is a legacy app riddled with char(10) and such), or even if a key that is a string is left null.

Question
I want to know if there is any reasonable or accepted way of enforcing the validation. I've found this question which might help debugging, but I would like to enforce the constraints in code

Is there any better method than changing every auto property to one that throws if it's constraints aren't met?

Austin_Anderson
  • 900
  • 6
  • 16

2 Answers2

1

EntityFramework Core does not enforce any validation at all. The validation rules you see in the example are enforced by MVC and not EF. One of the main reason for EF Core to remove validation check was that only. Validation are run in UI and then in EF and then again in database which is just redundant. Hence client side validation is left to the front-end (MVC in this case) and server side is done by database engine.

When you use database first approach, EF core does not generate any annotation for validation because it does not reason about them anyway. That means you would get only server side validation which means error during SaveChanges.

The only way to enforce constraint in the code (client side) is to write those annotations so that MVC can enforce them or write custom code to deal with it. The whole validation mechanism is transparent to EF.

Smit
  • 2,279
  • 1
  • 12
  • 22
  • but we are writing a json-rpc over http database api to replace our old stored procedure architecture, not a website. So the point remains that sqlserver's validation error message is utterly worthless, and I need a solution, like maybe extend the code generation tooling to add the validation automatically – Austin_Anderson Aug 10 '17 at 03:29
  • Regardless of it is website or not, your framework to provide API is doing validation since EF just won't. Since validations in code are business logic, it is not easy to deduce them from database hence database first won't generate them by itself. You can either write extra code after model is generated from database or try modifying the code writer in EF core. Though the former would be much easier. – Smit Aug 10 '17 at 05:13
  • mainly the type of constraints I'm worried about are things like it `char(10)` in the db, but the property is just string, so those type would be quite simple to deduce from the db, but I guess I'll need to add it myself – Austin_Anderson Aug 10 '17 at 05:18
  • You could use data annotations for generated code which can help certain cases like `nvarchar(10)` would actually scaffold `StringLength(10)` annotation. But in the end, the logic varies with each customer. And once you start adding some validation scaffolded, people ask for more and more logic to be included which could easily turn into complex feature. And all of these when EF actually does not respect those validation at all. – Smit Aug 10 '17 at 05:24
  • It is a good idea for external library which would extend EF's code generation and provide hooks for customer to give logic and scaffold validation annotations. – Smit Aug 10 '17 at 05:25
0

I ended up going with a psuedo extension to the generator tooling. Since the DBContext is a partial class, I made a new class that has a main

public partial class DBContext{
    public static void Main(string[]args){
        DBContext context = new DBContext();
        var modelbuilder = new Microsoft.EntityFrameworkCore.ModelBuilder(new Microsoft.EntityFrameworkCore.Metadata.Conventions.ConventionSet());
        context.OnModelCreating(modelbuilder);
        IMutableModel model=modelbuilder.Model;

from there I used Linq to transform the various info about each entity's properties and the annotations on them into List<KeyValuePair<string,List<KeyValuePair<Regex,string>>>> where the first pair's key is the entity name, and the value is a list of find and replace pairs to edit the code that had already been generated with the corresponding validation, one per property. Then all I had to do was abuse the fact that the tooling generates the classes in <className>.cs files, and iterate over my list, executing the replacements for each entity source code file.

I'd have preferred doing something a little less hacky, because I'm relying on format that the ef tooling outputs, but it works

Austin_Anderson
  • 900
  • 6
  • 16