我有一个界面,用于定义消费者可以使用的DbSets,例如:
public interface IMyContext : IDisposable
{
IDbSet<Regional> Regionals { get; set; }
IDbSet<Unit> Units { get; set; }
int SaveChanges();
}
我们决定创建这个接口,以便能够将任何实现注入其他类,这有助于测试。
这是几分钟前的实施:
public sealed class MyContext : DbContext, IMyContext
{
public IDbSet<Regional> Regionals { get; set; }
public IDbSet<Unit> Units { get; set; }
}
非常简单的东西。
今天,在处理一些相关的类时,我决定将这些属性转换为显式实现,如果没有键入接口,则禁止访问。
public sealed class MyContext : DbContext, IMyContext
{
IDbSet<Regional> IMyContext.Regionals { get; set; }
IDbSet<Unit> IMyContext.Units { get; set; }
}
一旦我改变并尝试添加新的迁移,我就得到了一个例外:
System.Data.Entity.ModelConfiguration.ModelValidationException: One or more validation errors were detected during model generation:
\tSystem.Data.Entity.Edm.EdmEntitySet: Name: The specified name is not allowed: 'MyProject.IMyContext.Regionals'.
\tSystem.Data.Entity.Edm.EdmEntitySet: Name: The specified name is not allowed: 'MyProject.IMyContext.Units'.
at System.Data.Entity.ModelConfiguration.Edm.EdmModelExtensions.ValidateAndSerializeCsdl(EdmModel model, XmlWriter writer)
at System.Data.Entity.DbModelBuilder.Build(DbProviderManifest providerManifest, DbProviderInfo providerInfo)
at System.Data.Entity.DbModelBuilder.Build(DbConnection providerConnection)
at System.Data.Entity.Internal.LazyInternalContext.CreateModel(LazyInternalContext internalContext)
at System.Data.Entity.Internal.RetryLazy`2.GetValue(TInput input)
at System.Data.Entity.Internal.LazyInternalContext.InitializeContext()
at System.Data.Entity.Internal.LazyInternalContext.get_CodeFirstModel()
at System.Data.Entity.Infrastructure.EdmxWriter.WriteEdmx(DbContext context, XmlWriter writer)
at System.Data.Entity.Migrations.Extensions.DbContextExtensions.<>c__DisplayClass1.<GetModel>b__0(XmlWriter w)
at System.Data.Entity.Migrations.Extensions.DbContextExtensions.GetModel(Action`1 writeXml)
at System.Data.Entity.Migrations.Extensions.DbContextExtensions.GetModel(DbContext context)
at System.Data.Entity.Migrations.DbMigrator..ctor(DbMigrationsConfiguration configuration, DbContext usersContext)
at System.Data.Entity.Migrations.DbMigrator..ctor(DbMigrationsConfiguration configuration)
at System.Data.Entity.Migrations.Design.ToolingFacade.BaseRunner.GetMigrator()
at System.Data.Entity.Migrations.Design.ToolingFacade.GetPendingMigrationsRunner.RunCore()
at System.Data.Entity.Migrations.Design.ToolingFacade.BaseRunner.Run()
One or more validation errors were detected during model generation:
\tSystem.Data.Entity.Edm.EdmEntitySet: Name: The specified name is not allowed: 'MyProject.IMyContext.Regionals'.
\tSystem.Data.Entity.Edm.EdmEntitySet: Name: The specified name is not allowed: 'MyProject.IMyContext.Units'.
这里发生了什么?看起来EF Migration不能再从属性中推断出EntitySet名称,因为它们现在是显式实现。如果我使用OnModelCreating
方法覆盖它起作用的实体集名称:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Unit>().HasEntitySetName("Units");
modelBuilder.Entity<Regional>().HasEntitySetName("Regionals");
}
我显然想要避免这种情况,并像以前一样自动使用属性名称。这是EF中的错误还是预期的行为?
环境正在使用带有.Net 4的EF 5。
更新
我已经证实了我对反射返回属性名称的怀疑,对于显式实现的属性不同。我使用LINQPad完成了一个简单的测试,现在是:
public interface ITest
{
string Prop1 {get; set;}
string Prop2 {get; set;}
}
public class Test : ITest
{
string ITest.Prop1 {get; set;}
public string Prop2 {get; set;}
}
void Main()
{
var properties = typeof(Test).GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
Console.WriteLine(String.Join(", ", properties.Select(_=>_.Name)));
}
需要绑定标志,因为显式属性实现是内部的,但隐式属性是公共的。
这是输出:
UserQuery.ITest.Prop1, Prop2
我没有看EF的代码,但我想它会使用这种反射来构建实体集名称。我个人认为这是一个错误。仍然希望听到EF人们对此的看法。