我正在尝试使用EF6.1.3代码优先迁移为接口建立一些默认约定,但基于接口的约定似乎被区别对待。 Conventions operate in a last wins manner。或者至少他们通常会这样做。
这是一个非常简单的数据库设计示例,其中所有字符串属性应限制为200个字符,但实现B
接口的类型除外,其中IName
和FirstName
属性应分别限制为50和100个字符。
LastName
这会在迁移代码中生成以下public interface IName
{
string FirstName { get; set; }
string LastName { get; set; }
}
public class Person : IName
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string EmailAddress { get; set; }
}
public class StringConvention : Convention
{
public StringConvention()
{
Properties<string>().Configure(c => c.HasMaxLength(200));
}
}
public class NameConvention : Convention
{
public NameConvention()
{
Types<IName>().Configure(c => c.Property(i => i.FirstName).HasMaxLength(50).IsRequired());
Types<IName>().Configure(c => c.Property(p => p.LastName).HasMaxLength(100).IsRequired());
}
}
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext()
: base()
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Conventions.Add<StringConvention>();
modelBuilder.Conventions.Add<NameConvention>();
modelBuilder.Entity<Person>();
}
}
语句:
CreateTable
CreateTable(
"dbo.People",
c => new
{
Id = c.Int(nullable: false, identity: true),
FirstName = c.String(nullable: false, maxLength: 200),
LastName = c.String(nullable: false, maxLength: 200),
EmailAddress = c.String(maxLength: 200),
})
.PrimaryKey(t => t.Id);
明确执行为NameConvention
,FirstName
标记为不可为空(通过LastName
),但IsRequired()
不会覆盖{ {1}}尽管maxLength
是最后一个。
如果StringConvention
直接代替NameConvention
而不是NameConvention
界面,那么一切都按预期工作。
Person
在迁移代码中生成以下IName
语句:
public class NameConvention : Convention
{
public NameConvention()
{
Types<Person>().Configure(c => c.Property(i => i.FirstName).HasMaxLength(50).IsRequired());
Types<Person>().Configure(c => c.Property(p => p.LastName).HasMaxLength(100).IsRequired());
}
}
我想使用约定来通过单独的类库中的接口来建立默认值而不是具体类型,使用配置让消费项目使用配置覆盖它们但我似乎无法弄清楚为什么{{1}在这种情况下被忽略了。
答案 0 :(得分:0)
冒着完全回答被问到的问题的风险......
我遇到了类似的问题,其中MaxLength约定由于EF6x错误而恢复了IsUnicode()约定(抱歉,我没有链接)。
我的解决方案是使用AddAfter&lt;&gt;()扩展方法配置约定。对于您的代码,它看起来像这样:
...
...
modelBuilder.Conventions.Add<StringConvention>();
modelBuilder.Conventions.AddAfter<StringConvention>(new NameConvention());
...
...
也就是说,我的约定并不局限于接口类型,因此类比不是完全匹配,但应该很容易验证。
SC
答案 1 :(得分:0)
我找到了另一种方法来实现我的默认最大长度约定,允许我的基于接口的约定覆盖默认值:
我将基于Convention
的{{1}}替换为StringConvention
实施:
IConceptualModelConvention<EntityType>
然后我确保在public class StringDefaultMaxLengthConvention : IConceptualModelConvention<EntityType>, IConvention
{
private int DefaultMaxLength { get; set; }
public StringDefaultMaxLengthConvention()
: this(200)
{
}
public StringDefaultMaxLengthConvention(int defaultMaxLength)
{
DefaultMaxLength = defaultMaxLength;
}
public void Apply(EntityType item, DbModel model)
{
PrimitiveType stringPrimitiveType = PrimitiveType.GetEdmPrimitiveType(PrimitiveTypeKind.String);
foreach (var property in item.DeclaredProperties.Where(p => p.IsPrimitiveType && p.PrimitiveType == stringPrimitiveType))
{
if (!property.MaxLength.HasValue && !property.IsMaxLength)
{
property.MaxLength = DefaultMaxLength;
}
}
}
}
之前添加它,因为该约定将所有内容标记为PropertyMaxLengthConvention
:
IsMaxLength
我更喜欢能够将原始想法发挥作用,因为我更喜欢使用流畅的API配置和约定,但如果没有,我可以忍受这个。