【问题标题】:Setting one-to-one relationship设置一对一关系
【发布时间】:2014-11-25 22:45:35
【问题描述】:

如何在Entity Framework的code-first中使用fluent API正确设置一对一关系?

根模型是Project 类。每个项目都包含一个报价。它还可以选择包含一个客户订单。

历史模型的目的是包含各个非历史行的快照(当添加Project 时,会创建一个新的Project,然后将其复制到一个新的ProjectHistorical 类中,如果它是编辑后,将创建一个新的ProjectHistorical 类,其中填充了编辑后的Project 的数据)。 历史对象应该是AutoMapper 友好的。您可以将历史模型视为一种愚蠢、琐碎和幼稚的解决方法,因为数据库引擎中不支持时态数据库。

使用此配置,我遇到以下困难:

  1. CustomerOrdersOffers 表及其历史 对应对象生成了一个Project_Id 列。我没找到办法 如何强制使用Id 主键或注释 ProjectId 属性(我更喜欢使用注释过的ProjectId 属性)。
  2. ProjectHistoricals 表有 生成CustomerOrder_IdOffer_Id 列。我没找到办法 如何强制使用Id 列(请注意,Id 列不是历史表的主键)或注释 CustomerOrderIdOfferId 列(在 ProjectProjectHistorical类;我更喜欢使用带注释的CustomerOrderIdOfferId 列)。

我尝试了很多搜索并尝试了更多的东西,但没有达到(我本来)预期的效果。

我有以下型号:

public class Project
{
  public virtual int Id { get; set; }
  // public virtual int OfferId { get; set; }
  public virtual Offer Offer { get; set; }
  // public virtual int? CustomerOrderId { get; set; }
  public virtual CustomerOrder CustomerOrder { get; set; }
}

public class ProjectHistorical
{
  public virtual int LogId { get; set; }
  public virtual int Id { get; set; }
  // public virtual int OfferId { get; set; }
  public virtual Offer Offer { get; set; }
  // public virtual int? CustomerOrderId { get; set; }
  public virtual CustomerOrder CustomerOrder { get; set; }
}

public class CustomerOrder 
{
  public virtual int Id { get; set; }
  // public virtual int ProjectId { get; set; }
  public virtual Project Project { get; set; }
}

public class CustomerOrderHistorical
{
  public virtual int LogId { get; set; }
  public virtual int Id { get; set; }
  // public virtual int ProjectId { get; set; }
  public virtual Project Project { get; set; }
}

public class Offer
{
  public virtual int Id { get; set; }
  // public virtual int ProjectId { get; set; }
  public virtual Project Project { get; set; }
}

public class OfferHistorical
{
  public virtual int LogId { get; set; }
  public virtual int Id { get; set; }
  // public virtual int ProjectId { get; set; }
  public virtual Project Project { get; set; }
}

以及以下 fluent api(主键必须始终命名为 Id,因为所有模型都实现了一个共享接口,而不是由应用程序的通用部分使用):

modelBuilder.Conventions.Remove<IdKeyDiscoveryConvention>();
modelBuilder.Conventions.Remove<ForeignKeyAssociationMultiplicityConvention>();
modelBuilder.Conventions.Remove<PrimaryKeyNameForeignKeyDiscoveryConvention>();
modelBuilder.Conventions.Remove<OneToOneConstraintIntroductionConvention>();
modelBuilder.Conventions.Remove<TypeNameForeignKeyDiscoveryConvention>();
modelBuilder.Conventions.Remove<AssociationInverseDiscoveryConvention>();
modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();

modelBuilder.Entity<CustomerOrder>().HasKey(t => t.Id);

modelBuilder.Entity<CustomerOrderHistorical>().HasKey(t => t.LogId);
modelBuilder.Entity<CustomerOrderHistorical>().HasRequired(t => t.Project);

modelBuilder.Entity<Offer>().HasKey(t => t.Id);

modelBuilder.Entity<OfferHistorical>().HasKey(t => t.LogId);
modelBuilder.Entity<OfferHistorical>().HasRequired(t => t.Project);

modelBuilder.Entity<Project>().HasKey(t => t.Id);
modelBuilder.Entity<Project>().HasRequired(t => t.Offer).WithRequiredPrincipal(t => t.Project);
modelBuilder.Entity<Project>().HasOptional(t => t.CustomerOrder).WithRequired(t => t.Project);

modelBuilder.Entity<ProjectHistorical>().HasKey(t => t.LogId);
modelBuilder.Entity<ProjectHistorical>().HasRequired(t => t.Offer);
modelBuilder.Entity<ProjectHistorical>().HasOptional(t => t.CustomerOrder);

这是实体框架将模型编译到数据库的方式:

        CreateTable(
            "dbo.CustomerOrderHistoricals",
            c => new
                {
                    LogId = c.Int(nullable: false, identity: true),
                    Id = c.Int(nullable: false),
                    Project_Id = c.Int(nullable: false),
                })
            .PrimaryKey(t => t.LogId)
            .ForeignKey("dbo.Projects", t => t.Project_Id)
            .Index(t => t.Project_Id);

        CreateTable(
            "dbo.Projects",
            c => new
                {
                    Id = c.Int(nullable: false, identity: true),
                })
            .PrimaryKey(t => t.Id);

        CreateTable(
            "dbo.CustomerOrders",
            c => new
                {
                    Id = c.Int(nullable: false, identity: true),
                    Project_Id = c.Int(nullable: false),
                })
            .PrimaryKey(t => t.Id)
            .ForeignKey("dbo.Projects", t => t.Project_Id)
            .Index(t => t.Project_Id);

        CreateTable(
            "dbo.Offers",
            c => new
                {
                    Id = c.Int(nullable: false, identity: true),
                    Project_Id = c.Int(nullable: false),
                })
            .PrimaryKey(t => t.Id)
            .ForeignKey("dbo.Projects", t => t.Project_Id)
            .Index(t => t.Project_Id);

        CreateTable(
            "dbo.OfferHistoricals",
            c => new
                {
                    LogId = c.Int(nullable: false, identity: true),
                    Id = c.Int(nullable: false),
                    Project_Id = c.Int(nullable: false),
                })
            .PrimaryKey(t => t.LogId)
            .ForeignKey("dbo.Projects", t => t.Project_Id)
            .Index(t => t.Project_Id);

        CreateTable(
            "dbo.ProjectHistoricals",
            c => new
                {
                    LogId = c.Int(nullable: false, identity: true),
                    Id = c.Int(nullable: false),
                    CustomerOrder_Id = c.Int(),
                    Offer_Id = c.Int(nullable: false),
                })
            .PrimaryKey(t => t.LogId)
            .ForeignKey("dbo.CustomerOrders", t => t.CustomerOrder_Id)
            .ForeignKey("dbo.Offers", t => t.Offer_Id)
            .Index(t => t.CustomerOrder_Id)
            .Index(t => t.Offer_Id);

【问题讨论】:

  • 你的数据模型正确吗?一对一的关系通常意味着这两个表应该合并到一个表中。
  • 我知道从理论的角度来看这应该是一样的。但是,从业务角度来看,Project、Offer 和 CustomerOrder 是不同的东西。您可以想象项目是一个包含多个文档的文件夹。另一个想象是,项目是一个工作流,其他模型的存在说明了您在流程中的哪一步(首先,您向客户创建报价,然后收到客户的订单,然后......) .

标签: c# sql-server entity-framework


【解决方案1】:

您可以阅读this tutorial 或查看stackoverflow 上的this answer 或MSDN 上的this answer

【讨论】:

  • 谢谢。我之前已经看过两篇链接的文章,但我会检查第二篇。 PS:最后一个链接不是stackoverflow上的答案。
  • 如果我正确理解了第二个链接,尤其是引用的文章weblogs.asp.net/manavi/… EF(至少在 4.1 版中)不合理地支持一对一的关系,所以我需要坚持作为一种解决方法,我已经完成了一对多的关系。还是我的理解有误? EF5/EF6 对此没有任何改变? PS:问题中没有说明。我的模型的主键需要在每个实体中命名为 Id。
  • 正确。坚持你的解决方法。我们也在研究一种解决方法:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-21
  • 1970-01-01
  • 1970-01-01
  • 2013-05-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多