Первый или нулевой код платформы Entity Framework First FluentApi
- Мне нужно создать fluentapi один или ноль к одной ссылке и иметь свойства навигации на обоих объектах.
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; }
}