属性隐藏时种子设定失败

本文关键字:失败 种子 隐藏 属性 | 更新日期: 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 团队改变这一点?似乎有点边缘情况。