【问题标题】:How to specify two navigation relations for ef/breeze ("Unable to determine a valid ordering")?如何为 ef/breeze 指定两个导航关系(“无法确定有效排序”)?
【发布时间】:2016-01-22 09:42:02
【问题描述】:

我以两种方式尊重实体“监控”:

  • 作为公司监控列表的一部分
  • 作为对公司的有效(= 当前选择)监控

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 并仅保存公司一次,我会收到以下错误:

无法确定相关操作的有效顺序。 由于外键约束,模型可能存在依赖关系 需求或存储生成的值。

以下是用于创建新公司的示例 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”使关系更加明确,但没有成功。我还发现了一些相关的 stackoverflow 问题,但我找不到针对我的具体问题的解决方案:

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

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

我还考虑过不将实例保存为活动监控,而只保存监控列表中活动监控的索引,例如“IndexOfActiveMonitoring”。但是,如果我想访问活动的监控,我需要一些额外的代码来查找活动的监控。

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

【问题讨论】:

    标签: c# entity-framework ef-code-first


    【解决方案1】:

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

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

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

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

      • 如果我更改测试代码以添加监控并将其设置为主动监控我收到我在问题中提到的错误消息:Company cmp = new Company() ; cmp.CompanyId = Guid.NewGuid();使用 (var db = new DatabaseContext()) { db.Companies.Add(cmp); var m1 = 新监控 { CompanyId = cmp.CompanyId, MonitoringId = Guid.NewGuid() }; db.Monitorings.Add(m1); cmp.ActiveMonitoring = m1; db.SaveChanges(); }
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-09-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多