我有两张桌子:
tblInvestment
{
InvestmentId char(10), --pk
PrimaryPerformanceId char(10)
}
tblPerformance
{
PerformanceId char(10), --pk,
InvestmentId char(10)
}
我为这两个表创建了2个实体clase:
[Table("tblInvestment")]
class Investment
{
[Key]
public string InvestmentId { get; set; }
public string PrimaryPerformanceId { get; set; }
[ForeignKey("PrimaryPerformanceId")]
public virtual Performance PrimaryPerformance { get; set; }
[ForeignKey("InvestmentId")]
public virtual ICollection<Performance> Performances { get; set; }
}
[Table("tblPerformance")]
class Performance
{
[Key]
public string PerformanceId { get; set; }
public string InvestmentId { get; set; }
[ForeignKey("InvestmentId")]
public virtual Investment Investment { get; set; }
}
当我为每个表创建一个新记录并调用DbContext.SaveChanges函数时,我得到一个异常说:“无法确定依赖操作的有效排序。由于外键约束,可能存在依赖关系,模型要求或商店生成的值。“ 但是,如果我删除Investment.PrimaryPerformance属性,我可以将记录保存到数据库。为什么呢?
using(MyContext db = new MyContext)
{
var inv = db.Investments.Add(new Investment{
InvestmentId = "1",
PrimaryPerformance = new Performance{
PerformanceId = "A",
InvestmentId = "1"
}
};
db.SaveChanges();
}
这是堆栈信息:
System.Data.Mapping.Update.Internal.UpdateTranslator.DependencyOrderingError(IEnumerable`1 剩余) System.Data.Mapping.Update.Internal.UpdateTranslator.ProduceCommands() System.Data.Mapping.Update.Internal.UpdateTranslator.Update(IEntityStateManager stateManager,IEntityAdapter适配器) System.Data.EntityClient.EntityAdapter.Update(IEntityStateManager entityCache)System.Data.Objects.ObjectContext.SaveChanges(SaveOptions options)System.Data.Entity.Internal.InternalContext.SaveChanges() System.Data.Entity.Internal.InternalContext.SaveChanges() System.Data.Entity.Internal.LazyInternalContext.SaveChanges() System.Data.Entity.DbContext.SaveChanges()
答案 0 :(得分:1)
我认为问题出现在你的模型中,你有一个双重外键“Performance”==&gt;
[ForeignKey("PrimaryPerformanceId")]
public virtual Performance PrimaryPerformance { get; set; }
[ForeignKey("InvestmentId")]
public virtual ICollection<Performance> Performances { get; set; }
我认为你必须删除其中一个...
答案 1 :(得分:0)
来自MSDN:
如果放在外键属性上,则关联的名称 导航属性。如果放在导航属性上,则名称为 相关的外键。
您只需要关联同一个类中的相关字段(如果它们与命名约定不匹配)。您这样做是为了告诉Code First它们属于相同的外键关系。 Code First非常聪明,可以自行确定Relation的主键,因为您已在相关类中指定了Key
属性。
所以你的模型应该是这样的:
[Table("tblInvestment")]
class Investment
{
[Key]
public string InvestmentId { get; set; }
[ForeignKey("PrimaryPerformance")]
public string PrimaryPerformanceId { get; set; } // This is the foreign key property
public virtual Performance PrimaryPerformance { get; set; } // This is the navigation property
public virtual ICollection<Performance> Performances { get; set; }
}
[Table("tblPerformance")]
class Performance
{
[Key]
public string PerformanceId { get; set; }
public virtual Investment Investment { get; set; }
}
答案 2 :(得分:0)
好的,首先,你需要更正你的对象模型,因为它给你一个不正确的Db架构,就像它现在的样子一样。如果查看生成的模式,您将看到EF在tblPerformance上创建了另一个InvestmentId(名称为Investment_InvestmentId)。您需要做的就是指定您在Investment.Performances和Performance.Investment属性所代表的投资和绩效类之间的关联是双向的。
如果您更喜欢流畅的API上的数据注释(看起来如此),那么您需要使用 InverseProperty 属性,如下所示:
[Table("tblPerformance")]
class Performance
{
[Key]
public string PerformanceId { get; set; }
public string InvestmentId { get; set; }
[InverseProperty("Performances")]
public virtual Investment Investment { get; set; }
}
现在,您获得的例外非常正常。考虑一下,你要求EF在一个事务中为你添加两个对象:一个具有主要性能对象的投资对象,因此EF首先尝试插入性能记录,以获得投资对象的PrimaryPerformanceId(使用InvestmentId) = 1),但随后它注意到绩效记录也需要与投资相同的投资对象(Id = 1)。哪一个会先走?在一次交易中不可能。
因此,使其工作的唯一方法是使用两个事务来添加对象:
using(Context db = new Context())
{
var inv = db.Investments.Add(new Investment() { InvestmentId = "1"});
db.SaveChanges();
inv.PrimaryPerformance = new Performance()
{
PerformanceId = "A",
InvestmentId = "1"
};
db.SaveChanges();
}
这段代码运行得很好。
注意:我使用最新的EF版本来运行此代码(v4.3.1)。所以如果你还没有,请更新你的二进制文件。
答案 3 :(得分:0)
TryTopologicalSort函数抛出异常,我想这个函数用于计算记录之间的依赖关系。它只支持实体之间的一种关系。