5

Po prostu najpierw używam kodu Entity Framework 4.1 i zamiast tego chciałbym zastąpić moje atrybuty [ForeignKey (..)] płynnymi wywołaniami w modelu ModelBuilder. Coś podobnego do WithRequired (..) i HasForeignKey (..) poniżej, które wiążą jawną właściwość klucza obcego (CreatedBySessionId) wraz z powiązaną właściwością nawigacji (CreatedBySession). Ale chciałbym to zrobić na jeden do jednego relationsip zamiast jednego do wielu:Kod EF 4.1 Najpierw ModelBuilder HasForeignKey dla pojedynczych relacji

modelBuilder.Entity<..>().HasMany(..).WithRequired(x => x.CreatedBySession).HasForeignKey(x => x.CreatedBySessionId) 

Bardziej konkretnym przykładem jest poniżej. Działa to całkiem szczęśliwie za pomocą atrybutu [ForeignKey (..)], ale chciałbym go usunąć i skonfigurować go wyłącznie na modelbuilder.

public class VendorApplication 
{ 
    public int VendorApplicationId { get; set; } 

    public int CreatedBySessionId { get; set; } 
    public virtual Session CreatedBySession { get; set; } 
} 

public class Session 
{ 
    public int SessionId { get; set; } 

    [ForeignKey("CurrentApplication")] 
    public int? CurrentApplicationId { get; set; } 
    public virtual VendorApplication CurrentApplication { get; set; } 

    public virtual ICollection<VendorApplication> Applications { get; set; } 
} 

public class MyDataContext: DbContext 
{ 
    public IDbSet<VendorApplication> Applications { get; set; } 
    public IDbSet<Session> Sessions { get; set; } 

    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     modelBuilder.Entity<Session>().HasMany(x => x.Applications).WithRequired(x => x.CreatedBySession).HasForeignKey(x => x.CreatedBySessionId).WillCascadeOnDelete(false); 
     // Note: We have to turn off Cascade delete on Session <-> VendorApplication relationship so that SQL doesn't complain about cyclic cascading deletes 
    } 
} 

Tutaj Sesja może być odpowiedzialny za tworzenie wielu VendorApplications (Session.Applications), ale sesja pracuje na co najwyżej jeden VendorApplication naraz (Session.CurrentApplication). Chciałbym powiązać właściwość CurrentApplicationId z właściwością nawigacji CurrentApplication w modelBuilder zamiast za pomocą atrybutu [ForeignKey (..)].

Czego próbowałem

Po wyjęciu [ForeignKey (..)] przypisują własnością CurrentApplication generuje kolumnę CurrentApplication_VendorApplicationId w bazie danych, który nie jest przywiązany do kolumny CurrentApplicationId.

Próbowałem jawnie mapowania relacji używając nazwy kolumny CurrentApplicationId jak poniżej, ale oczywiście to generuje błąd, ponieważ nazwa kolumny w bazie „CurrentApplicationId” jest już używana przez nieruchomości w Session.CurrentApplicationId:

modelBuilder.Entity<Session>().HasOptional(x => x.CurrentApplication).WithOptionalDependent().Map(config => config.MapKey("CurrentApplicationId")); 

Czuję, że brakuje tu czegoś bardzo oczywistego, ponieważ wszystko, co chcę zrobić, to wykonać tę samą operację, którą wykonuje [ForeignKey (..)], ale w obrębie programu budującego model. Czy jest to przypadek, że jest to zła praktyka i została wyraźnie pominięta?

Odpowiedz

10

Należy odwzorować relację jako jeden do wielu i pominąć właściwość kolekcji w relacji.

modelBuilder.Entity<Session>() 
    .HasOptional(x => x.CurrentApplication) 
    .WithMany() 
    .HasForeignKey(x => x.CurrentApplicationId) 
+1

Tak, to jest to! Wcześniej grałem z tą konfiguracją, ale EF wyrzucił wyjątek dotyczący wielokrotności konfliktów, więc ustaliłem, że relacja musi wynosić 1: 1. Oczywiście teraz zdaję sobie sprawę, że konflikt mnogości faktycznie się wydarzył, ponieważ pierwotnie miałem CurrentApplicationId jako non-nullable ... ** (face palm) **. Dzięki za pomoc, bardzo docenione! – Walter