我正在使用Entity Framework 6,Code-First和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);
}
}
每个Code-First Entity实现以下简单接口:
public interface IEntity
{
int Id { get; }
}
现在假设我有以下实体:
public class MyEntity : IEntity
{
public int Id { get; set; }
public string Name { get; set; }
}
我在DbContext
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new MyEntityConfiguration());
}
使用实体的配置类:
public class MyEntityConfiguration : EntityTypeConfiguration<MyEntity>
{
public MyEntityConfiguration()
{
this.HasPrimaryKey()
}
}
奇怪的是,当我在程序包管理器控制台中执行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:\path\ConfigurationExtensions.cs
这很奇怪,因为当我将扩展方法中的代码重构为构造函数时,就像这样:
public class MyEntityConfiguration : EntityTypeConfiguration<MyEntity>
{
public MyEntityConfiguration()
{
HasKey(m => m.Id)
.Property(t => t.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
}
}
然后,框架不会抛出异常,一切都按预期工作。为什么?框架错误?
答案 0 :(得分:2)
异常消息具有误导性。实际问题非常简单。 EF仅支持具有属性设置器的属性。
由于泛型扩展方法中的表达式m => m.Id
绑定到Id
接口的IEntity
属性,该接口没有setter(与实现类相比),EF不会将其视为有效属性,并使用有关属性类型的误导性消息抛出异常。
要修复它,只需在界面中为Id
属性定义setter:
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);
}
}