我有一个项目,我正在使用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约束。
先谢谢你们!
答案 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);