【发布时间】:2014-11-25 22:45:35
【问题描述】:
如何在Entity Framework的code-first中使用fluent API正确设置一对一关系?
根模型是Project 类。每个项目都包含一个报价。它还可以选择包含一个客户订单。
历史模型的目的是包含各个非历史行的快照(当添加Project 时,会创建一个新的Project,然后将其复制到一个新的ProjectHistorical 类中,如果它是编辑后,将创建一个新的ProjectHistorical 类,其中填充了编辑后的Project 的数据)。
历史对象应该是AutoMapper 友好的。您可以将历史模型视为一种愚蠢、琐碎和幼稚的解决方法,因为数据库引擎中不支持时态数据库。
使用此配置,我遇到以下困难:
-
CustomerOrders和Offers表及其历史 对应对象生成了一个Project_Id列。我没找到办法 如何强制使用Id主键或注释ProjectId属性(我更喜欢使用注释过的ProjectId属性)。 -
ProjectHistoricals表有 生成CustomerOrder_Id和Offer_Id列。我没找到办法 如何强制使用Id列(请注意,Id列不是历史表的主键)或注释CustomerOrderId和OfferId列(在Project和ProjectHistorical类;我更喜欢使用带注释的CustomerOrderId和OfferId列)。
我尝试了很多搜索并尝试了更多的东西,但没有达到(我本来)预期的效果。
我有以下型号:
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