I find myself repeating many many times the same attributes I apply to properties of classes, that are used to represent both entity framework entities AND objects that will be edited in Blazor client forms (but it could be anything else, I think).
Trying to save me some typing (and probably also errors) I googled around to find some technique to minimize the code I write.
I ended up finding this solution:
Combining multiple Attributes to a single Attribute - Merge Attributes
That's really helpful to me for the editing phase. When I use such approach on properties that will be edited in Blazor forms, I get all the attribute-related errors if it's the case, and all works.
Unfortunately, apparently this approach is not taken into account by the Entity Framework migration generator, so, unless I made some big error, they use two different (sub)technologies to generate constraints for the given property.
(Example: I apply to a string property 'Required', 'MinLength' and 'MaxLength' attributes through my custom metadata attribute, as per the linked article, and the field is generated in the migration without any of these constraints, although they are applied in a form)
Indeed, I can use custom conventions, to obtain the same result on the side of entity framework (something explained for example in https://learn.microsoft.com/en-us/ef/ef6/modeling/code-first/conventions/custom), but this would mean that I would have to apply two different attributes/approaches to the same property, each time (also risking to mis-align things...).
It looks so strange, to me... Any ideas, from anyone, please?
*** Update
After the motivated answer by Chris, that I really thank, I can add a more realistic example, from the (test) code I'm writing.
[Required]
[MinLength(Constants.ShortStringFieldMinLength, ErrorMessage = Constants.ShortStringFieldMinLengthErrorMessage)]
[MaxLength(Constants.ShortStringFieldMaxLength, ErrorMessage = Constants.ShortStringFieldMaxLengthErrorMessage))]
[RegularExpression(Constants.ShortNameRegEx, ErrorMessage = Constants.ShortNameRegExError)]
[DisplayName("Name of something")]
public string Name { get; set; } = string.Empty;
[Required]
[MinLength(Constants.LongStringFieldMinLength, ErrorMessage = Constants.LongStringFieldMinLengthErrorMessage)]
[MaxLength(Constants.LongStringFieldMaxLength, ErrorMessage = Constants.LongStringFieldMaxLengthErrorMessage))]
[RegularExpression(Constants.LongStringFieldRegEx, ErrorMessage = Constants.LongStringFieldRegExErrorMessage)]
[DisplayName("Description of something")]
public string Description{ get; set; } = string.Empty;
A long entity object described in this way is really less than readable, other than repeating many times the same declaration for many of the properties (long string fields and short string fields, fundamentally... maybe also 'medium', with time?).
It would much better if I could write:
[ShortStringField("Name of something")]
public string Name {get; set; } = string.Empty;
[LongStringField("Description of something")]
public string Description {get; set; } = string.Empty;
Am I overengineering? :-) Maybe! I just find much more pleasant the second syntax, if I can get to it, someway.
I obviously know that some of the attributes will be applied only to editing (DisplayName, for example), but I'm ok with that, of course.
Given that there are two solutions for the two different parts of the problem, I was just wondering if there's an architectural way to reach both services together: maybe the resulting code can be a little bit complex, but it would be just a one shot, obviously, and the reuse very easy and flexible.