【问题标题】:Entity Framework Code First One to Zero or One Relationship With Separate Identity实体框架代码第一个一对零或一个具有单独身份的关系
【发布时间】:2019-01-21 09:58:43
【问题描述】:

我有两个这样的课程:

public class Event
{
    [Key]
    [Required]
    public long Id { get; set; }

    [InverseProperty("Event")          
    public virtual Record Record{ get; set; }
}


public class Record
{
    [Key]
    [Required]
    public int Id { get; set; }

    [ForeignKey("Event")]
    public long? EventId { get; set; }

    public virtual Event Event{ get; set; }
}

但是,我在此设置中得到了预期的多重性错误。我想结束的是:

  • 没有记录而存在的事件

  • 没有事件的现有记录

  • 事件与记录一起存在(并让记录存储事件 ID)

这可能吗?我是否必须使用FluentApi 而不是Data Annotations

我不想在事件表中添加任何字段或键。

【问题讨论】:

  • EF6 还是 EF Core?

标签: entity-framework foreign-keys ef-code-first multiplicity


【解决方案1】:

在 EF 6.x 中,您必须使用 Fluent API 进行如下配置:

 modelBuilder.Entity<Record>()
       .HasOptional(x => x.Event)
       .WithOptionalPrincipal(x => x.Record)
       .Map(a => a.MapKey("RecordId"));

在 EF Core 中,您当前的模型设置已经足够好了!不需要再做任何事情了。

【讨论】:

    【解决方案2】:

    你是对的,只给关系的两侧之一一个外键。我首先认为双方都需要一个可为空的外键。但是,如果您这样做,那么事件 1 可能具有记录 2 的外键,事件 3 的外键和记录 4 的外键,等等。

    显然在这些情况下,只有两侧应该有一个外键。

    configure one-to-zero-or-one relation,看到以下就够了:

    class Event
    {
        public long Id { get; set; }
        public string Name { get; set; }
    
        // Every Event has zero or one Record
        public virtual Record Record { get; set; }
    }
    class Record
    {
        public long Id { get; set; }
        public string Name { get; set; }
    
        // Every Record has zero or one Event
        public virtual Event Event { get; set; }
    }
    

    还有 DbContext:

    class OneToOneContext : DbContext
    {
        public OneToOneContext(): base("OneToOneDemo"){}
    
        public DbSet<Event> Events { get; set; }
        public DbSet<Record> Records { get; set; }
    
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
    
            modelBuilder.Entity<Record>()
                .HasOptional(record => record.Event)
                .WithOptionalDependent(ev => ev.Record)
                .WillCascadeOnDelete(false);
        }
    }
    

    fluent API 通知模型构建器每个 Record 都有零个或一个 Event,有零个或一个 Record。记录被声明为依赖。这确保 Record 在这个关系中会有外来的。

    请注意,我不必添加任何其他属性。因为我遵循code first conventions实体框架能够检测到主键和表之间的关系。

    我能够添加:没有记录的事件、没有事件的记录、有记录的事件和有事件的记录:

    using (var dbContext = new OneToOneContext())
    {
        dbContext.Events.Add(new Event { Name = "Event without Record"});
        dbContext.Records.Add(new Record { Name = "Record without Event" });
    
        dbContext.Events.Add(new Event
        {
            Name = "Event A with Record",
            Record = new Record { Name = "Record of Event A" },
        });
    
        dbContext.Records.Add(new Record
        {
            Name = "Record B with Event",
            Event = new Event { Name = "Event of Record B" },
        });
    
        dbContext.SaveChanges();
    }
    

    【讨论】:

    • 您好,这主要以我想要的方式工作,并将为迁移搭建支架并允许我使用导航属性,但是当我们使用服务/回购模式时,我将单独保存这些实体。例如,事件在记录之前添加,因此在保存记录时,我将只有事件 ID(由于服务/回购模式混淆了它),理想情况下只想将事件 ID 附加到记录并保存它。另一种方法是我必须查询事件表并将该实体拉出并附加它。
    • @Sep,您是否尝试过我的解决方案来克服您面临的问题?
    • @TanvirArjel 嗨,不幸的是,当我这样做时,它也会在 Event 表中添加一列,我需要避免这样做,因为它已经是一个大表了。
    • @Seb 可能如果不将列添加到Entity Framework 6.X 的事件表中是不可能的,但您可以在EF Core 中执行此操作
    • @TanvirArjel 我明白了,很遗憾我们还没有准备好迁移到 EF Core!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-05-04
    • 1970-01-01
    • 1970-01-01
    • 2012-10-26
    • 1970-01-01
    • 2020-01-31
    • 1970-01-01
    相关资源
    最近更新 更多