1

我有一个使用 EF5 的项目,我制作了一个自定义 Guid 生成器,并且我重写了 SaveChanges 方法来分配我的实体的 ID。

一切正常,除了在一种情况下:当一个实体的 ID 是另一个实体的另一个 ID 的 FK 时。

一点代码来解释这个问题:

我有两个无法更改的实体:

public class FixedEntityA
{
    public Guid Id { get; set;}
    public string SomeText { get; set; }
}

public class FixedEntityB
{
    public Guid Id { get; set;}
    public int OneInt { get; set; }
}    

在我的项目中,我有一个这样定义的实体:

public class ComposedEntity
{
    public Guid Id { get; set;}
    public FixedEntityA FixedA { get; set; }
    public FixedEntityB FixedB { get; set; }
    public double OneDouble { get; set; }
}       

关系是:

ComposedEntity 可能有 0 或 1 个 FixedEntityA

ComposedEntity 可能有 0 或 1 个 FixedEntityB

对 id 的约束是:

FixedEntityA 的 Id 是指向 ComposedEntity 的 Id 的 FK

FixedEntityB 的 Id 是指向 ComposedEntity 的 Id 的 FK

映射类是:

public ComposedEntity(): EntityTypeConfiguration<ComposedEntity>
{
    HasOptional(fea => fea.FixedA).WithRequired();
    HasOptional(feb => feb.FixedB).WithRequired();
}

这是我的 SaveChanges 覆盖:

foreach (var entry in ChangeTracker.Entries<IEntity>().Where(e => e.State == EntityState.Added))
{
   Type t = entry.Entity.GetType();

   List<DatabaseGeneratedAttribute> info = t.GetProperty("Id")
                                            .GetCustomAttributes(typeof (DatabaseGeneratedAttribute), true)
                                            .Cast<DatabaseGeneratedAttribute>().ToList();

   if (!info.Any() || info.Single().DatabaseGeneratedOption != DatabaseGeneratedOption.Identity)
   {
       if (entry.Entity.Id == Guid.Empty)
            entry.Entity.Id = (Guid) _idGenerator.Generate();
   }
}
return base.SaveChanges();

此代码适用于所有类型的关系,除了在这种情况下,我错过了一个测试,以确保我没有在作为外键的 id 上设置 id,并且我不知道如何检查 Id 是否是一个FK...

这是此代码失败的示例对象:

var fea = new FixedEntityA();
var feb = new FixedEntityB();
var composedEntity = new ComposedEntity();

composedEntity.FixedA = fea;
composedEntity.FixedB = feb;

如果插入整个图形,所有三个对象都标记为已添加,并且所有 Id 都是默认值。

问题是,使用当前的 SaveChanges 方法,我将遍历更改跟踪器中具有已添加状态的所有对象,并且我将为具有默认 Guid 的所有实体分配一个 Id 并打破我的 FK 约束。

提前谢谢各位!

4

1 回答 1

2

这里有一些代码可以获取给定类型的 FK 属性(我知道这很可怕)。应该足够简单,可以将其插入您的代码中。

var typeName = "Category";

var fkProperties = ((IObjectContextAdapter)db)
    .ObjectContext
    .MetadataWorkspace
    .GetItems<AssociationType>(DataSpace.CSpace)
    .Where(a => a.IsForeignKey)
    .Select(a => a.ReferentialConstraints.Single())
    .Where(c => c.FromRole.GetEntityType().Name == typeName)
    .SelectMany(c => c.FromProperties)
    .Select(p => p.Name);
于 2013-04-09T23:36:52.270 回答