EF Core能否在迁移中使用MetadataType?

huangapple go评论65阅读模式
英文:

Can EF Core use MetadataType for migrations?

问题

EF Core 在创建数据库迁移时是否能够尊重 MetadataType 注解,比如 MaxLength 等?

我创建了一个人员类,并用 MetadataType 进行了装饰,但在添加数据库迁移时,这些注解似乎没有被考虑进去。

英文:

Is there a way to get EF Core to honour MetadataType annotations for MaxLength etc when creating DB migrations?

I've created a person class and decorated it with MetadataType but the annotations aren't considered when I add a DB migration.

答案1

得分: 1

以下是翻译的内容:

"Meanwhile, in case you are using EF Core 7.0 or later, you can utilize the Model building conventions and implement it yourself."

"同时,如果您正在使用EF Core 7.0或更高版本,您可以利用模型构建约定,并自己实现它。"

"First method is just for convenience, the actual work is inside ProcessPropertyAdded switch. I've added support for 3 attributes, other can be added if needed in a similar fashion."

"第一个方法只是为了方便,实际工作在ProcessPropertyAdded开关内。我已经为3个属性添加了支持,如果需要的话,可以以类似的方式添加其他属性。"

"With this code in place, all you need is to override ConfigureConventions in your derived DbContext class and include AddMetadaTypeAttributeSupport call, e.g."

"有了这段代码,您只需要在派生的DbContext类中重写ConfigureConventions,并包括AddMetadaTypeAttributeSupport调用,例如:"

protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
    base.ConfigureConventions(configurationBuilder);
    configurationBuilder.AddMetadaTypeAttributeSupport();
}
英文:

These are not considered at all, not only during the migration. They (EF Core team) do not find a value for implementing such functionality given the multiple alternative options they provide - entity type configuration classes (close to MetadataType classes, but with fluent API), OnModelCreating, custom model conventions (ConfigureConventions) etc.

Actually as you have found later, there is an open issue Conventions should honor [MetadataType] #14544 in EF Core issue tracker, but as of time of writing (EF Core 7.0) it's not considered to be addressed, which kind of proves my initial thoughts.

Meanwhile, in case you are using EF Core 7.0 or later, you can utilize the Model building conventions and implement it yourself.

Following is a sample implementation:

using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.EntityFrameworkCore.Metadata.Conventions;

using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;

namespace Microsoft.EntityFrameworkCore
{
    public static class ModelConfigurationBuilderExtensions
    {
        public static ModelConfigurationBuilder AddMetadaTypeAttributeSupport(this ModelConfigurationBuilder configurationBuilder)
        {
            configurationBuilder.Conventions.Add(sp => new MetadataTypeAttrubuteConvention());
            return configurationBuilder;
        }
    }
}

namespace Microsoft.EntityFrameworkCore.Metadata.Conventions
{
    public class MetadataTypeAttrubuteConvention : IPropertyAddedConvention
    {
        public void ProcessPropertyAdded(IConventionPropertyBuilder propertyBuilder, IConventionContext<IConventionPropertyBuilder> context)
        {
            var property = propertyBuilder.Metadata;
            foreach (var metaProp in property.DeclaringEntityType.ClrType
                .GetCustomAttributes<MetadataTypeAttribute>(true)
                .SelectMany(metaType => metaType.MetadataClassType.GetProperties())
                .Where(metaProp => metaProp.Name == property.Name
                    && metaProp.PropertyType.IsAssignableFrom(property.ClrType)))
            {
                foreach (var metaAttr in metaProp.GetCustomAttributes(true))
                {
                    switch (metaAttr)
                    {
                        case RequiredAttribute dataAttr:
                            propertyBuilder.IsRequired(true, fromDataAnnotation: true);
                            break;
                        case MaxLengthAttribute dataAttr:
                            if (dataAttr.Length > 0)
                                propertyBuilder.HasMaxLength(dataAttr.Length, fromDataAnnotation: true);
                            break;
                        case PrecisionAttribute dataAttr:
                            propertyBuilder.HasPrecision(dataAttr.Precision, fromDataAnnotation: true);
                            if (dataAttr.Scale.HasValue)
                                propertyBuilder.HasScale(dataAttr.Scale, fromDataAnnotation: true);
                            break;
                    }
                }
            }
        }
    }
}

First method is just for convenience, the actual work is inside ProcessPropertyAdded switch. I've added support for 3 attributes, other can be added if needed in a similar fashion.

With this code in place, all you need is to override ConfigureConventions in your derived DbContext class and include AddMetadaTypeAttributeSupport call, e.g.

protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
    base.ConfigureConventions(configurationBuilder);
    configurationBuilder.AddMetadaTypeAttributeSupport();
}

huangapple
  • 本文由 发表于 2023年3月4日 06:59:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/75632556.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定