Первый или нулевой код платформы Entity Framework First FluentApi

  1. Мне нужно создать fluentapi один или ноль к одной ссылке и иметь свойства навигации на обоих объектах.
  2. EntityTwo должен содержать простое свойство для хранения внешнего ключа (EntityOneId)

    public class EntityOne
    {
        public int Id { get; set; }
        public EntityTwo EntityTwo { get; set; }
    }
    
    public class EntityTwo
    {
        public int Id { get; set; }
        public int EntityOneId { get; set; }
        public EntityOne EntityOne { get; set; }
    }
    
    public class MyDbContext : DbContext
    {
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            //some code trimmed
    
            modelBuilder.Entity<EntityOne>()
                .HasOptional(entity => entity.EntityTwo)
                .WithRequired();
    
            modelBuilder.Entity<EntityTwo>()
                .HasRequired(entity => entity.EntityOne)
                .WithMany()
                .HasForeignKey(entity => entity.EntityOneId)
                .WillCascadeOnDelete(false);
        }
    }
    

более сложный сценарий:

public class EntityOne
{
    public int Id { get; set; }

    public EntityTwo EntityTwo { get; set; }
}

public class EntityThree
{
    public int Id { get; set; }

    public EntityTwo EntityTwo { get; set; }
}

public class EntityTwo
{
    public int Id { get; set; }

    public int EntityOneId { get; set; }

    public EntityOne EntityOne { get; set; }

    public int EntityThreeId { get; set; }

    public EntityThree EntityThree { get; set; }
}

public class MyDbContext : DbContext
{
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        //some code trimmed

        modelBuilder.Entity<EntityOne>()
            .HasOptional(entity => entity.EntityTwo)
            .WithRequired();

        modelBuilder.Entity<EntityThree>()
            .HasOptional(entity => entity.EntityTwo)
            .WithRequired();

        modelBuilder.Entity<EntityTwo>()
            .HasRequired(entity => entity.EntityOne)
            .WithMany()
            .HasForeignKey(entity => entity.EntityOneId)
            .WillCascadeOnDelete(false);

        modelBuilder.Entity<EntityTwo>()
            .HasRequired(entity => entity.EntityThree)
            .WithMany()
            .HasForeignKey(entity => entity.EntityThreeId)
            .WillCascadeOnDelete(false);
    }
}

2 ответа

В отношении "один к одному" один конец должен быть основным, а второй конец должен быть зависимым. Основной конец - это тот, который будет вставлен первым и может существовать без зависимого. Зависимый конец - тот, который должен быть вставлен после принципала, потому что у него есть внешний ключ к принципалу. При настройке отношений один-к-одному Entity Framework требует, чтобы первичный ключ зависимого также был внешним ключом. Правильный способ достичь того, чего вы хотите, может быть таким, но использует аннотации данных:

public class EntityOne
{
  public int Id { get; set; }
  public virtual EntityTwo EntityTwo { get; set; }
}

 public class EntityTwo
 {
   [Key, ForeignKey("EntityOne")]
   public int EntityOneId { get; set; }
   public virtual EntityOne EntityOne { get; set; }
}

Я предлагаю вам проверить эту ссылку, вы можете найти там больше информации о том, как работают отношения один-к-одному в EF Code First.

Обновить:

Я боюсь, что то, что вы хотите, не возможно. Вы не можете создать отношение один к одному с FK, который не объявлен как PK. Если вы хотите, чтобы каждая сущность имела свою собственную Id настроить отношение один-к-одному между этими двумя объектами, затем удалить свойство FK в EntityTwo,

Я рекомендую сопоставить эти отношения с помощью Fluent Api, как показано ниже:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<EntityTwo>()
        .HasRequired(et => et.EntityOne)
        .WithOptional(eo=>eo.EntityTwo);
}

Или вы можете просто добавить Required Атрибут для свойства навигации, которое является основным, например:

public class EntityTwo
{
  public int Id { get; set; }
  // public int EntityOneId { get; set; }
  [Required]
  public EntityOne EntityOne { get; set; }
}

Единственный способ справиться с этим, который, по общему признанию, несколько уродлив, состоит в том, чтобы создать коллекцию и вспомогательное свойство для представления стороны "один / ноль". Данные аннотации включены для наглядности.

public class EntityOne
{
    [Key]
    public int EntityOneId { get; set; }

    public EntityTwo EntityTwo => EntityTwoNavigation?.FirstOrDefault();
    public ICollection<EntityTwo> EntityTwoNavigation { get; set; }
}

public class EntityTwo
{
    [Key]
    public int EntityTwoId { get; set; }
    public int EntityOneId { get; set; }

    [ForeignKey("EntityOneId")]
    public EntityOne EntityOne { get; set; }
}
Другие вопросы по тегам