Мы хотим использовать необязательные отношения один к одному, используя Entity Framework Code First. У нас есть две сущности.
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 не создавал никаких внешних ключей в этих двух таблицах.
У вас есть идеи по этому поводу? Как мы можем создать необязательные отношения один-к-одному, используя Fluent API Entity Framework?
источник
WithOptional
? Чем отличается отWithRequiredDependent
иWithRequiredOptional
?Просто сделайте это так, как если бы между вами была связь "один ко многим",
LoyaltyUserDetail
иPIIUser
поэтому отображение должно бытьEF должен создать весь необходимый вам внешний ключ и просто не заботиться о WithMany !
источник
В вашем коде есть несколько ошибок.
1: 1 отношения либо: ПК <-PK , где одна сторона ПК также ФК или ПК <-fk + UC , где сторона FK не-ПК и имеет UC. Ваш код показывает, что у вас FK <-FK , поскольку вы определяете, что обе стороны имеют FK, но это неправильно. Я разведываю
PIIUser
на стороне ПК иLoyaltyUserDetail
на стороне ФК. Это означает, что уPIIUser
него нет поля FK, ноLoyaltyUserDetail
есть.Если соотношение 1: 1 является необязательным, сторона FK должна иметь как минимум 1 поле, допускающее значение NULL.
pswg выше ответил на ваш вопрос, но сделал ошибку, так как он / она также определил FK в PIIUser, что, конечно, неправильно, как я описал выше. Поэтому определите поле FK, допускающее обнуление, в
LoyaltyUserDetail
, определите атрибут,LoyaltyUserDetail
чтобы пометить его как поле FK, но не указывайте поле FK вPIIUser
.Вы получите исключение, которое вы описали выше под сообщением pswg, потому что никакая сторона не является стороной PK (основной конец).
EF не очень хорош в соотношении 1: 1, поскольку не может обрабатывать уникальные ограничения. Я не специалист по коду в первую очередь, поэтому я не знаю, может ли он создать UC или нет.
(править) кстати: A 1: 1 B (FK) означает, что создано только 1 ограничение FK для цели B, указывающей на PK A, а не 2.
источник
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);
это решит проблему с ССЫЛКАМИ и ИНОСТРАННЫМИ КЛЮЧАМИ
при ОБНОВЛЕНИИ или УДАЛЕНИИ записи
источник
Попробуйте добавить
ForeignKey
атрибут к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; } ... }
источник
ForeignKey
атрибут только к одному концу отношения? т.е. только наPIIUser
илиLoyaltyUserDetail
.Единственное, что сбивает с толку вышеупомянутые решения, заключается в том, что первичный ключ определяется как « 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; } }
А затем последовало
Сделал бы трюк, принятое решение не может четко объяснить это, и это отбросило меня на несколько часов, чтобы найти причину.
источник
Это бесполезно для оригинального плаката, но для тех, кто все еще использует EF6, кому нужно, чтобы внешний ключ отличался от первичного, вот как это сделать:
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; } } modelBuilder.Entity<PIIUser>() .HasRequired(t => t.LoyaltyUserDetail) .WithOptional(t => t.PIIUser) .Map(m => m.MapKey("LoyaltyUserDetailId"));
Обратите внимание, что вы не можете использовать это
LoyaltyUserDetailId
поле, потому что, насколько я могу судить, его можно указать только с помощью свободного API. (Я пробовал три способа сделать это с помощьюForeignKey
атрибута, и ни один из них не работал).источник