dotnet / efcore

EF Core is a modern object-database mapper for .NET. It supports LINQ queries, change tracking, updates, and schema migrations.
https://docs.microsoft.com/ef/
MIT License
13.81k stars 3.2k forks source link

EF Core should honor attributes from implemented interfaces #34779

Open AlexBaggett opened 2 months ago

AlexBaggett commented 2 months ago

EF Core should honor [MaxLength] attributes from interfaces an Entity Implements

It's less useful and frustrating for a user of EFCore to spend a lot of time developing Interfaces for defining categories of Entities which include a [MaxLength] attribute on a property of the interface, only to find that the migration generated has a nvarchar max column type, and thus have to go back and manually add [MaxLength] to each property on each entity that implements that interface.

Honestly, a user of EF Core would intuitively expect this work. And it's both surprising and frustrating that it doesn't.

here is an example:

    public interface IReferenceData
    {
        [MaxLength(512)]
        public string ReferenceId { get; set; }
    }
    public class MyEntity: IReferenceData
    {
       public required string ReferenceId {get; set;}
    }

EF will generate a migration for that has ReferenceId as nvarchar(max)

I'd like EF to use reflection to check scan for interfaces an entity implements and get a list of properties from those interfaces, if they have a max length attribute on them, apply them to their counterpart property in the entity.

So that it will generate an appropriate sized column based on the interface and improved the usefulness and value proposition of using Entity Framework Core in general.

Here is a Naive implementation:


protected void SetUpMaxLengthViaInterfaces(ModelBuilder modelBuilder)
{
    foreach (var entityType in modelBuilder.Model.GetEntityTypes())
    {
        var clrType = entityType.ClrType;
        var interfaces = clrType.GetInterfaces();

        foreach (var interfaceType in interfaces)
        {
            var interfaceProperties = interfaceType.GetProperties();

            foreach (var interfaceProperty in interfaceProperties)
            {
                var maxLengthAttribute = interfaceProperty.GetCustomAttribute<MaxLengthAttribute>();
                if (maxLengthAttribute != null)
                {
                    var entityProperty = clrType.GetProperty(interfaceProperty.Name);
                    if (entityProperty != null)
                    {
                        modelBuilder.Entity(clrType)
                            .Property(entityProperty.Name)
                            .HasMaxLength(maxLengthAttribute.Length);
                    }
                }
            }
        }
    }
}
AndriySvyryd commented 1 month ago

Related to #14544