Один к одному необязательное отношение с помощью Entity Framework Fluent API
Сначала мы хотим использовать одно к одному необязательное отношение с использованием кода Entity Framework. У нас есть две сущности.
public class PIIUser
{
public int Id { get; set; }
public int? LoyaltyUserDetailId { get; set; }
public LoyaltyUserDetail LoyaltyUserDetail { get; set; }
}
public class LoyaltyUserDetail
{
public int Id { get; set; }
public double? AvailablePoints { get; set; }
public int PIIUserId { get; set; }
public PIIUser PIIUser { get; set; }
}
PIIUser
может быть LoyaltyUserDetail
но LoyaltyUserDetail
должен быть PIIUser
.
Мы попробовали эти методы беглого подхода.
modelBuilder.Entity<PIIUser>()
.HasOptional(t => t.LoyaltyUserDetail)
.WithOptionalPrincipal(t => t.PIIUser)
.WillCascadeOnDelete(true);
этот подход не создавал LoyaltyUserDetailId
внешний ключ в PIIUsers
таблица.
после этого мы попробовали следующий код.
modelBuilder.Entity<LoyaltyUserDetail>()
.HasRequired(t => t.PIIUser)
.WithRequiredDependent(t => t.LoyaltyUserDetail);
но на этот раз EF не создал никаких внешних ключей в этих 2 таблицы.
у вас есть какие-либо идеи по этому вопросу? Как мы можем создать один к одному необязательные отношения с помощью entity framework fluent api?
6 ответов:
EF код сначала поддерживает
1:1
и1:0..1
отношения. Последняя является то, что вы ищете ("один к нулю или одному").ваши попытки свободно говорить требуются на обоих концах в одном случае и дополнительно на обоих концах в другой.
что нужно дополнительно и требуются С другой стороны.
вот пример из первой книги кода программирования E. F.
modelBuilder.Entity<PersonPhoto>() .HasRequired(p => p.PhotoOf) .WithOptional(p => p.Photo);
The
PersonPhoto
сущность имеет свойство навигации под названиемPhotoOf
это указывает наPerson
тип. ЭлементPerson
тип имеет свойство навигации под названиемPhoto
кPersonPhoto
тип.в двух связанных классах вы используете каждый тип первичный ключ, а не внешние ключи. т. е., вы не будете использовать
LoyaltyUserDetailId
илиPIIUserId
свойства. Вместо этого отношение зависит отId
поля обоих типов.если вы используете fluent API, как указано выше, вам не нужно указывать
LoyaltyUser.Id
как внешний ключ, EF поймет это.так что без вашего кода, чтобы проверить себя (я ненавижу делать это из моей головы)... Я бы перевел это в ваш код как
public class PIIUser { public int Id { get; set; } public LoyaltyUserDetail LoyaltyUserDetail { get; set; } } public class LoyaltyUserDetail { public int Id { get; set; } public double? AvailablePoints { get; set; } public PIIUser PIIUser { get; set; } } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Entity<LoyaltyUserDetail>() .HasRequired(lu => lu.PIIUser ) .WithOptional(pi => pi.LoyaltyUserDetail ); }
это говорит LoyaltyUserDetails
PIIUser
недвижимость требуются и PIIUser этоLoyaltyUserDetail
свойство является необязательным.вы можете начать с другой конец:
modelBuilder.Entity<PIIUser>() .HasOptional(pi => pi.LoyaltyUserDetail) .WithRequired(lu => lu.PIIUser);
который теперь говорит Piiuser's
LoyaltyUserDetail
свойство является необязательным и LoyaltyUser по свойства.вы всегда должны использовать шаблон имеет/С.
HTH и FWIW, один к одному (или один к нулю/один) отношения являются одним из самых запутанных отношений для настройки в коде сначала, так что вы не одиноки! :)
просто нравится, если у вас есть один-ко-многим отношения между
LoyaltyUserDetail
иPIIUser
Так что вы отображение должно бытьmodelBuilder.Entity<LoyaltyUserDetail>() .HasRequired(m => m.PIIUser ) .WithMany() .HasForeignKey(c => c.LoyaltyUserDetailId);
EF должен создать все внешние ключи вам нужно и просто не волнуйтесь о WithMany !
есть несколько вещей неправильно с вашим кодом.
A 1:1 отношения-это: PK, где одна сторона PK также является FK, или PK, где сторона FK не является PK и имеет UC. Ваш код показывает, что у вас есть FK, как вы определяете обе стороны, чтобы иметь FK, но это неправильно. Я разведчик
PIIUser
Это сторона ПК иLoyaltyUserDetail
- это сторона FK. Это значитPIIUser
не имеет поля FK, ноLoyaltyUserDetail
делает.если 1:1 связь необязательна, сторона FK должна иметь по крайней мере 1 поле с нулевым значением.
P.s.w.g. выше ответил на ваш вопрос, но сделал ошибку, Что s/he также определил FK в PIIUser, что, конечно, неправильно, как я описал выше. поэтому определите поле FK с нулевым значением в
LoyaltyUserDetail
определите атрибутLoyaltyUserDetail
чтобы отметить это поле FK, но не указывайте поле FK вPIIUser
.вы получаете исключение опишите выше ниже поста p.s.w.g., потому что ни одна сторона не является стороной PK (принцип конца).
EF не очень хорош в 1: 1, поскольку он не может обрабатывать уникальные ограничения. я не эксперт по коду во-первых, поэтому я не знаю, Может ли он создать UC или нет.
(edit) кстати: A 1:1 B (FK) означает, что существует только 1 ограничение FK, созданное на цели B, указывающей на PK A, а не на 2.
попробуйте добавить до
LoyaltyUserDetail
свойства:public class PIIUser { ... public int? LoyaltyUserDetailId { get; set; } [ForeignKey("LoyaltyUserDetailId")] public LoyaltyUserDetail LoyaltyUserDetail { get; set; } ... }
и
PIIUser
свойства:public class LoyaltyUserDetail { ... public int PIIUserId { get; set; } [ForeignKey("PIIUserId")] public PIIUser PIIUser { get; set; } ... }
public class User { public int Id { get; set; } public int? LoyaltyUserId { get; set; } public virtual LoyaltyUser LoyaltyUser { get; set; } } public class LoyaltyUser { public int Id { get; set; } public virtual User MainUser { get; set; } } modelBuilder.Entity<User>() .HasOptional(x => x.LoyaltyUser) .WithOptionalDependent(c => c.MainUser) .WillCascadeOnDelete(false);
это решит проблему на ссылка и ВНЕШНИЕ КЛЮЧИ
, когда обновление или удаление запись
одна вещь, которая путается с вышеуказанными решениями, заключается в том, что первичный ключ определяется как " Id" в обеих таблицах, и если у вас есть первичный ключ, основанный на имени таблицы, это не сработает, я изменил классы, чтобы проиллюстрировать то же самое, т. е. необязательная таблица не должна определять свой собственный первичный ключ вместо этого должна использовать одно и то же имя ключа из основной таблицы.
public class PIIUser { // For illustration purpose I have named the PK as PIIUserId instead of Id // public int Id { get; set; } public int PIIUserId { get; set; } public int? LoyaltyUserDetailId { get; set; } public LoyaltyUserDetail LoyaltyUserDetail { get; set; } } public class LoyaltyUserDetail { // Note: You cannot define a new Primary key separately as it would create one to many relationship // public int LoyaltyUserDetailId { get; set; } // Instead you would reuse the PIIUserId from the primary table, and you can mark this as Primary Key as well as foreign key to PIIUser table public int PIIUserId { get; set; } public double? AvailablePoints { get; set; } public int PIIUserId { get; set; } public PIIUser PIIUser { get; set; } }
и затем
modelBuilder.Entity<PIIUser>() .HasOptional(pi => pi.LoyaltyUserDetail) .WithRequired(lu => lu.PIIUser);
сделал бы трюк, принятое решение терпит неудачу чтобы четко объяснить это, и это сбило меня с толку на несколько часов, чтобы найти причину