当id是带有自定义id生成器的fk时,如何不分配id

时间:2013-03-12 09:09:25

标签: entity-framework ef-code-first entity-framework-5

我有一个项目,我正在使用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约束。

先谢谢你们!

1 个答案:

答案 0 :(得分: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);