实体框架迁移在使用Fluent API的扩展方法时会引发异常



我正在使用实体框架6,code-firt with fluent-api。

我有以下扩展方法来设置我的实体的主要键:

public static class ConfigurationExtensions
{
    public static void HasPrimaryKey<TEntityType>(this EntityTypeConfiguration<TEntityType> configuration)
        where TEntityType : class, IEntity
    {
        configuration
            .HasKey(m => m.Id)
            .Property(t => t.Id)
            .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
    }
}

在每个代码优先实体实现以下简单接口时:

public interface IEntity
{
    int Id { get; }
}

现在假设我有以下实体:

public class MyEntity : IEntity
{
    public int Id { get; set; }
    public string Name { get; set; }
}

我正在使用fluent-api配置在我的 DbContext

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Configurations.Add(new MyEntityConfiguration());
}

带有实体的配置类:

public class MyEntityConfiguration : EntityTypeConfiguration<MyEntity>
{
    public MyEntityConfiguration()
    {
        this.HasPrimaryKey()
    }
}

奇怪的是,当我在 package Manager console 中执行Add-Migration时,我会得到以下例外:

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.InvalidOperationException: The property 'Id' cannot be used as a key property on the entity 'MyEntity' because the property type is not a valid key type. Only scalar types, string and byte[] are supported key types.
   at System.Data.Entity.ModelConfiguration.Configuration.Types.EntityTypeConfiguration.Key(PropertyInfo propertyInfo, Nullable`1 overridableConfigurationParts)
   at System.Data.Entity.ModelConfiguration.Configuration.Types.EntityTypeConfiguration.Key(IEnumerable`1 keyProperties)
   at System.Data.Entity.ModelConfiguration.EntityTypeConfiguration`1.HasKey[TKey](Expression`1 keyExpression)
   at ConfigurationExtensions.HasPrimaryKey[TEntityType](EntityTypeConfiguration`1 configuration) in C:pathConfigurationExtensions.cs

这很奇怪,因为当我重构扩展方法中的代码回到构造函数中时,如下:

public class MyEntityConfiguration : EntityTypeConfiguration<MyEntity>
{
    public MyEntityConfiguration()
    {
        HasKey(m => m.Id)
        .Property(t => t.Id)
        .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
    }
}

然后,框架不会抛出异常,一切都按预期工作。为什么?框架错误?

异常消息具有误导性。实际问题非常微不足道。EF仅支持具有属性设置器的属性。

由于您的通用扩展方法中的表达式m => m.Id绑定到IEntity接口的Id属性,该界面没有设置器(与实现类相比(,因此EF不认为它是有效的属性,并与误导性抛出异常有关属性类型的消息。

要修复它,只需为接口内的Id属性定义设置器:

public interface IEntity
{
    int Id { get; set; }
}

也可以通过使用Expression类方法手动构建Lambda表达式来解决,但是我认为修改接口更容易:)但是,在这里是完整的,如果您不想打破接口设计:

public static class ConfigurationExtensions
{
    public static void HasPrimaryKey<TEntityType>(this EntityTypeConfiguration<TEntityType> configuration)
        where TEntityType : class, IEntity
    {
        var parameter = Expression.Parameter(typeof(TEntityType), "m");
        var keyProperty = Expression.Lambda<Func<TEntityType, int>>(Expression.Property(parameter, nameof(IEntity.Id)), parameter);
        configuration
            .HasKey(keyProperty)
            .Property(keyProperty)
            .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
    }
}

最新更新