ef/breeze("Unable to determine a valid ordering")如何指定两个导航关系?

How to specify two navigation relations for ef/breeze ("Unable to determine a valid ordering")?

我从两个方面尊重一个实体"monitoring":


public class Company
  {
    [Key]
    [DataMember]
    public virtual Guid CompanyId { get; set; }

    [DataMember]
    public virtual Guid? MonitoringId { get; set; }

    [DataMember]
    [ForeignKey("MonitoringId")]
    public virtual Monitoring ActiveMonitoring { get; set; }

    [DataMember]   
    public virtual ICollection<Monitoring> Monitorings { get; set; }  
  }

public class Monitoring
  {
    [Key]
    [DataMember]
    public virtual Guid MonitoringId { get; set; }

    [DataMember]
    public virtual Guid CompanyId { get; set; }

    [DataMember]
    [ForeignKey("CompanyId")]   
    public virtual Company Company { get; set; } 
 }

如果我创建一个新的公司并在监控列表中添加一个新的监控,我可以轻而易举地保存它。保存新公司后,我可以将已添加的监控设置为 ActiveMonitoring 并再次保存公司。

但是,如果我尝试添加监控 并将其设置为 ActiveMonitioring 并只保存公司一次,我会收到以下错误:

Unable to determine a valid ordering for dependent operations. Dependencies may exist due to foreign key constraints, model requirements, or store-generated values.

下面是创建新公司的示例 JavaScript 代码:

var company = unitofwork.companyRepository.create();
var monitoring = unitofwork.monitoringRepository.create();

//add monitoring to the list of monitorings
monitoring.company(company);
company.monitorings.push(monitoring);

//set monitoring as active monitoring
company.activeMonitoring(monitoring);

unitofwork.commit();

我使用 EntityFramework 6 和 Breeze 1.5.4

我尝试使用注解"InverseProperty"使关系更明确但没有成功。我还发现了一些相关的 Whosebug 问题,但我找不到针对我的特定问题的解决方案:

我的 类 允许以下情况:监控可以是一家公司列表的一部分,并被设置为另一家公司的活动监控。但是,我不想允许这种情况:只有当监控也是同一公司的监控列表的一部分时,才应允许它成为主动监控。这是我问题的根本原因吗?

监控是否需要两次提及公司,例如CompanyForListReference 和 CompanyForActiveReference?或者是否有只适用于一个 CompanyId 的解决方案?

我也想过不把一个实例保存为活跃的监控,而是在监控列表中只保存活跃监控的索引,例如"IndexOfActiveMonitoring"。但是,如果我想访问活动监控,我需要一些额外的代码来查找活动监控。

=> 实施从公司到监控的两个引用的推荐方法是什么?

我只能说Entity Framework这一部分,但总体问题是一样的。出现此问题是因为命令的顺序很奇怪,您需要 运行 才能添加行 - 不可能一步完成。您需要插入公司行(您可以同时添加监控列表),然后调用 savechanges。这会生成实体的 ID,然后您可以使用这些来更新相关 ID。

EF 不够聪明,无法了解在单个实体上执行多项操作,在这些情况下,您需要使用显式事务并多次调用 SaveChanges。使用 EF-only,这将类似于:

using (var trans = new TransactionScope())
{
    Company company = new Company();   // ... populate
    company.Monitorings.Add(new Monitoring());
    company.Monitorings.Add(new Monitoring());

    context.Companies.Add(company);
    context.SaveChanges();

    company.ActiveMonitoring = company.Monitorings.First();
    context.SaveChanges();

    trans.Complete()
}

我已经修改了你的类,做了一个示例代码,结果成功了:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;

namespace TestApp
{
  public class Company
  {
      [Key]
      public virtual Guid CompanyId { get; set; }

      public virtual Guid? MonitoringId { get; set; }

      [ForeignKey("MonitoringId")]
      [InverseProperty("Companies")]
      public virtual Monitoring ActiveMonitoring { get; set; }

      [InverseProperty("Company")]
      public virtual ICollection<Monitoring> Monitorings { get; set; }
  }

  public class Monitoring
  {
      [Key]
      public virtual Guid MonitoringId { get; set; }

      public virtual Guid CompanyId { get; set; }

      [ForeignKey("CompanyId")]
      [InverseProperty("Monitorings")]
      public virtual Company Company { get; set; }

      [InverseProperty("ActiveMonitoring")]
      public virtual ICollection<Company> Companies { get; set; }
  }

  public class DatabaseContext : DbContext
  {
      public DatabaseContext() : base("TestContext")
      {
      }

      public DbSet<Company> Companies { get; set; }

      public DbSet<Monitoring> Monitorings { get; set; }
  }

  class Program
  {
      static void Main(string[] args)
      {
          Company cmp = new Company();
          cmp.CompanyId = Guid.NewGuid();

          using (var db = new DatabaseContext())
          {
              db.Companies.Add(cmp);                

              db.Monitorings.Add(new Monitoring { CompanyId = cmp.CompanyId, MonitoringId = Guid.NewGuid() });
              db.Monitorings.Add(new Monitoring { CompanyId = cmp.CompanyId, MonitoringId = Guid.NewGuid() });

             var m1 = new Monitoring { CompanyId = cmp.CompanyId, MonitoringId = Guid.NewGuid() };
            db.Monitorings.Add(m1);

              db.Companies.Add(new Company { CompanyId = Guid.NewGuid() ,MonitoringId = m1.MonitoringId });


              db.SaveChanges();

          }

      }
  }
}