是否有一种方法来映射两个实体有一个对一个的关系可选双方使用流畅的API在实体框架6?
代码示例:
// Subscription (has FK OrderId)
this.HasOptional(t => t.Order)
.WithOptionalDependent(t => t.Subscription)
.HasForeignKey(d => d.OrderId); // does not compile
上下文:为什么我要这样做?我在一个现有的系统中工作,那里有购买订阅的付款订单。当支付订单时,将创建一个订阅并与之关联,这意味着订阅对于订单是可选的。此外,还有其他方法可以创建订阅,这意味着订阅顺序是可选的。
通常在一对一(或零)关系中,两个实体共享相同的PK,在依赖关系中,PK也指定为FK。点击这个链接了解更多信息。但是如果实体不共享相同的PK,那么就不能在依赖实体中添加FK属性。如果这样做,EF将抛出一个与多重性相关的异常,表示它必须是*。
关于关系的配置,只有一种方法可以配置一个一对一的关系,双方都是可选的,这就是你目前使用Fluent Api的方法。这样,您还可以使用Map方法将EF按照约定在从属表中创建的FK列重命名为您在DB中的Subscription
表中已经拥有的名称。
如果您没有绑定到现有的数据库,您可以这样做:
public class Subscription
{
public int SubscriptionId { get; set; }
public int? OrderId { get; set; }
public virtual Order Order { get; set; }
}
public class Order
{
public int OrderId { get; set; }
public int SubscriptionId { get; set; }
public virtual Subscription Subscription { get; set; }
}
配置是这样的:
modelBuilder.Entity<Subscription>()
.HasOptional(s => s.Order)
.WithMany()
.HasForeignKey(s=>s.OrderId);
modelBuilder.Entity<>(Order)
.HasOptional(s => s.Subscription)
.WithMany()
.HasForeignKey(s=>s.SubscriptionId);
这样您就可以像处理一对一关系一样处理OrderId
FK(以及SubscriptionId
)。这里的问题是您必须分别设置和保存这两个关联
请在数据库上下文类
中尝试此代码 protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Subscription>()
.HasOptional(x => x.Order)
.WithOptionalPrincipal()
.Map(x => x.MapKey("SubscriptionId"));
modelBuilder.Entity<Order>()
.HasOptional(x => x.Subscription)
.WithOptionalPrincipal()
.Map(x => x.MapKey("OrderId"));
}
我的测试模型如下
public class Order
{
[Key]
public int OrderId { get; set; }
public string Description { get; set; }
public virtual Subscription Subscription { get; set; }
}
public class Subscription
{
[Key]
public int SubscriptionId { get; set; }
public virtual Order Order { get; set; }
}
编辑:我做了一个逆向工程数据库试图达到所需的代码结构通过使用双1对多关系的工作,就像你想要的。生成的代码如下所示。然而,这样做是个坏主意。
public partial class Order
{
public Order()
{
this.Subscriptions = new List<Subscription>();
}
public int OrderId { get; set; }
public string Description { get; set; }
public Nullable<int> SubscriptionId { get; set; }
public virtual Subscription Subscription { get; set; }
public virtual ICollection<Subscription> Subscriptions { get; set; }
}
public partial class Subscription
{
public Subscription()
{
this.Orders = new List<Order>();
}
public int SubscriptionId { get; set; }
public Nullable<int> OrderId { get; set; }
public virtual ICollection<Order> Orders { get; set; }
public virtual Order Order { get; set; }
}
public class OrderMap : EntityTypeConfiguration<Order>
{
public OrderMap()
{
// Primary Key
this.HasKey(t => t.OrderId);
// Properties
// Table & Column Mappings
this.ToTable("Orders");
this.Property(t => t.OrderId).HasColumnName("OrderId");
this.Property(t => t.Description).HasColumnName("Description");
this.Property(t => t.SubscriptionId).HasColumnName("SubscriptionId");
// Relationships
this.HasOptional(t => t.Subscription)
.WithMany(t => t.Orders)
.HasForeignKey(d => d.SubscriptionId);
}
}
public class SubscriptionMap : EntityTypeConfiguration<Subscription>
{
public SubscriptionMap()
{
// Primary Key
this.HasKey(t => t.SubscriptionId);
// Properties
// Table & Column Mappings
this.ToTable("Subscriptions");
this.Property(t => t.SubscriptionId).HasColumnName("SubscriptionId");
this.Property(t => t.OrderId).HasColumnName("OrderId");
// Relationships
this.HasOptional(t => t.Order)
.WithMany(t => t.Subscriptions)
.HasForeignKey(d => d.OrderId);
}
}
public partial class EFOrdersContextContext : DbContext
{
static EFOrdersContextContext()
{
Database.SetInitializer<EFOrdersContextContext>(null);
}
public EFOrdersContextContext()
: base("Name=EFOrdersContextContext")
{
}
public DbSet<Order> Orders { get; set; }
public DbSet<Subscription> Subscriptions { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new OrderMap());
modelBuilder.Configurations.Add(new SubscriptionMap());
}
}