2

I'm using EF Database First with an existing legacy database. Almost every field has a maxlength value in the database, and I can view this value in the .edmx file.

For example, on of the fields CCSTATUS is nvarchar(20). When the user inputs more than 20 chars, it clears ModelState.IsValid, but throws an DbEntityValidationException on db.SaveChanges().

For properties that I've added DataAnnotations to, when they fail to validate, they add model errors, which can then be displayed to the user so they can be corrected. I'm aware that I could add [MaxLength(n)] attributes to all of the properties in the Model MetaData classes, but is there a way to have EF add Model Errors instead of throwing DbEntityValidationException when a value is greater than the maxlength for the property?

EDIT

Thanks for the answers everyone. I ended up using EF Power Tools Reverse Engineer Code First feature to generate Code First models from my database, which included the appropriate maxlength attributes and other necessary annotations.

nb_
  • 507
  • 1
  • 5
  • 7
  • I don't know of any easy way to do that, but you can check this [link](http://www.headspring.com/entity-framework-code-first-dbcontext-validation/), and see if it helps – Nilesh Jul 29 '13 at 15:26

3 Answers3

3

The reason of this behavior is that EF and ASP.NET MVC are two different things. The ModelState is a concept of MVC and it has nothing to do with EF edmx metadata. If you want to use the same class to represent action input and a domain entity then you should go with the [MaxLength(n)] attribute solution. However, I would recommend to use a viewmodel/dto instead.

I wouldn't go with the solution of @Reinard (catching the DbEntityValidationException) for the following reasons: you are validating input and you are checking the result of the input validation inside the controller action. DbEntityValidationException indicates a problem at a completely different layer (database). This kind of layer mixing will hurt you sooner or later. Another reason is that you shouldn't use exceptions like this, but this is a different topic, e.g.: Why not use exceptions as regular flow of control?

Community
  • 1
  • 1
Peter Porfy
  • 8,561
  • 3
  • 30
  • 41
0

Why don't you catch the DbEntityValidationException and add a modelstate error? This will set ModelState.IsValid to false.

    try
    {
      repo.Save(model);
    }
    catch (DbEntityValidationException ex)
    {
      ModelState.AddModelError("EntityError", ex);
    }

You can expand on this and create a utility method that will log which fields caused the error:

foreach (var validationErrors in ex.EntityValidationErrors)
{
    foreach (var validationError in validationErrors.ValidationErrors)
    {
        string error = string.Format("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage);
    }
}

EDIT: As per Peter Porfy's answer I agree that you should avoid using Exceptions as part of your regular flow of control. Ideally you want to use the [MaxLength(n)] attribute and you could modify your T4 template to pick this up from the db when generating your pocos. Having said that, seeing that you're integrating with a legacy database I assume that schema changes might happen outside of the scope of "new" applications (like the one your developing), which means that exceptions like these might become more common, in which case the above code samples I provided might be useful. And whether you need to do code changes every time the schema change, or alternatively cater for that upfront (to some extent), I believe is a different argument altogether.

Community
  • 1
  • 1
Rei Mavronicolas
  • 1,295
  • 8
  • 12
0

I believe what you want is to modify the T4 template to add the DataAnnotation automatically.

tne
  • 6,417
  • 2
  • 38
  • 62