属性隐藏时种子设定失败
本文关键字:失败 种子 隐藏 属性 | 更新日期: 2023-09-27 17:55:55
这更像是一种思考练习。请考虑以下类:
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。
你可以...避免在涉及键属性时隐藏属性。:)
无论如何,如果您查看它们的源代码,当AddOrUpdate
使用给定的属性找到现有实体时(例如 r => r.Name
),它首先替换键属性,然后再使用 Entry(existing).CurrentValues.SetValues(entity)
更新非键属性。问题是它通过获取属性名称列表和过滤(.Where(p => p.Name == name)
)由 GetRuntimeProperties()
给出的列表来获取键属性,其中包括继承的属性。
也许另一种解决方案是让 EF 团队改变这一点?似乎有点边缘情况。