这比任何事都更像是一种思考。请考虑以下类:
public abstract class Entity : IEntity
{
public object Id { get; set; }
private string name;
[Required]
public string Name
{
get { return name ?? Guid.NewGuid().ToString(); }
set { name = value; }
}
private DateTime? createdDate;
[DataType(DataType.DateTime)]
public DateTime CreatedDate
{
get { return createdDate ?? DateTime.UtcNow; }
set { createdDate = value; }
}
[DataType(DataType.DateTime)]
public DateTime? ModifiedDate { get; set; }
public string CreatedBy { get; set; }
public string ModifiedBy { get; set; }
[Timestamp]
public Byte[] Version { get; set; }
}
public abstract class Entity<T> : Entity, IEntity<T>
{
[Key]
new public T Id
{
get { return base.Id != null ? (T)base.Id : default(T); }
set { base.Id = value; }
}
}
Entity<T>
隐藏Id
上的Entity
属性,将其替换为正确的类型。如果我从这里创建一个实体:
public class Foo : Entity<int>
{
...
}
并将其添加到上下文中:
public virtual IDbSet<Foo> Foos { get; set; }
实体框架愉快地创建了适当的表。所有核心EF函数都可以正常工作:我可以查询,保存,更新,删除等等。
但是,如果我尝试播种:
context.Foos.AddOrUpdate(
r => r.Name,
new Foo { ... },
new Foo { ... },
...
);
并运行update-database
。第一次,播种工作正常。然而,在每次后续运行中,播种都会引发异常:
Running Seed method.
System.Reflection.AmbiguousMatchException: Ambiguous match found.
at System.Data.Entity.Utilities.TypeExtensions.GetAnyProperty(Type type, String name)
at System.Data.Entity.Migrations.DbSetMigrationsExtensions.<>c__DisplayClass9`1.<GetKeyProperties>b__8(EdmMember km)
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
at System.Data.Entity.Migrations.DbSetMigrationsExtensions.AddOrUpdate[TEntity](DbSet`1 set, IEnumerable`1 identifyingProperties, InternalSet`1 internalSet, TEntity[] entities)
at System.Data.Entity.Migrations.DbSetMigrationsExtensions.AddOrUpdate[TEntity](IDbSet`1 set, Expression`1 identifierExpression, TEntity[] entities)
...
at System.Data.Entity.Migrations.DbMigrationsConfiguration`1.OnSeed(DbContext context)
at System.Data.Entity.Migrations.DbMigrator.SeedDatabase()
at System.Data.Entity.Migrations.Infrastructure.MigratorLoggingDecorator.SeedDatabase()
at System.Data.Entity.Migrations.DbMigrator.Upgrade(IEnumerable`1 pendingMigrations, String targetMigrationId, String lastMigrationId)
at System.Data.Entity.Migrations.Infrastructure.MigratorLoggingDecorator.Upgrade(IEnumerable`1 pendingMigrations, String targetMigrationId, String lastMigrationId)
at System.Data.Entity.Migrations.DbMigrator.UpdateInternal(String targetMigration)
at System.Data.Entity.Migrations.DbMigrator.<>c__DisplayClassc.<Update>b__b()
at System.Data.Entity.Migrations.DbMigrator.EnsureDatabaseExists(Action mustSucceedToKeepDatabase)
at System.Data.Entity.Migrations.Infrastructure.MigratorBase.EnsureDatabaseExists(Action mustSucceedToKeepDatabase)
at System.Data.Entity.Migrations.DbMigrator.Update(String targetMigration)
at System.Data.Entity.Migrations.Infrastructure.MigratorBase.Update(String targetMigration)
at System.Data.Entity.Migrations.Design.ToolingFacade.UpdateRunner.Run()
at System.AppDomain.DoCallBack(CrossAppDomainDelegate callBackDelegate)
at System.AppDomain.DoCallBack(CrossAppDomainDelegate callBackDelegate)
at System.Data.Entity.Migrations.Design.ToolingFacade.Run(BaseRunner runner)
at System.Data.Entity.Migrations.Design.ToolingFacade.Update(String targetMigration, Boolean force)
at System.Data.Entity.Migrations.UpdateDatabaseCommand.<>c__DisplayClass2.<.ctor>b__0()
at System.Data.Entity.Migrations.MigrationsDomainCommand.Execute(Action command)
Ambiguous match found.
现在,我理解为什么这种情况正在发生。 EF正在使用反射并获得Id
的两个结果,一个来自Entity
,另一个来自Entity<T>
。它无法确定使用哪个,并且失败。我的问题是:我能做些什么来帮助消除歧义吗?
对于它的价值,我正在运行EF 6.1.3。
答案 0 :(得分:0)
你可以......避免在涉及一个关键属性时隐藏属性。 :)
在任何情况下,如果你查看他们的源代码,当AddOrUpdate
找到使用给定属性的现有实体(例如r => r.Name
)时,它首先会替换关键属性,然后再使用{{1更新非键属性。问题是它通过获取属性名称和过滤 - Entry(existing).CurrentValues.SetValues(entity)
列表来获取关键属性 - GetRuntimeProperties()
给出的列表,其中包含继承的属性。< / p>
也许另一种解决方案是让EF团队改变它?看起来像是一个边缘案例。