实体框架中的关系(代码优先)

时间:2012-03-15 10:01:00

标签: c# entity-framework poco

我有两张桌子:

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()

4 个答案:

答案 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函数抛出异常,我想这个函数用于计算记录之间的依赖关系。它只支持实体之间的一种关系。