2012-04-11 10 views
11

Mam następujące dwa elementy, które próbuję powiązać (jeden do jednego) przy użyciu skojarzeń kluczy obcych.Kod struktury jednostki Najpierw: Konfigurowanie powiązania klucza obcego One-To-One za pomocą Adnotacji

public class StandardRack { 
    public int Id {get;set} 
    public StandardRelay StandardRelay {get;set} 
} 

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

    public int StandardRack_Id {get;set;} 
    [Required][ForeignKey("StandardRack_Id")] 
    public StandardRack StandardRack { get; set; } 
} 

To powoduje zgłoszenie wyjątku ModelValidationException. Wszelkie pomysły, dlaczego nie można skonfigurować tak pozornie prostej dwukierunkowej relacji jeden-do-jednego.

Edit:

Oto Wyjątek:

System.Data.Entity.ModelConfiguration.ModelValidationException został złapany Message = Jeden lub więcej błędów walidacji zostały wykryte podczas generacji modelu:

System.Data.Edm.EdmAssociationEnd:: Wielość nie jest poprawna w roli "StandardRelay_StandardRack_Source" w relacji "StandardRelay_StandardRack". Ponieważ właściwości Dependent Role nie są właściwościami kluczowymi, górna granica mnożności roli zależnej musi wynosić * .

Source = EntityFramework StackTrace: na System.Data.Entity.ModelConfiguration.Edm.EdmModelExtensions.ValidateAndSerializeCsdl (model EdmModel, XmlWriter pisarz) w System.Data.Entity.ModelConfiguration.Edm.EdmModelExtensions.ValidateCsdl (model EdmModel) w System.Data.Entity.DbModelBuilder.Build (DbProviderManifest providerManifest, DbProviderInfo providerInfo) w System.Data.Entity.DbModelBuilder.Build (DbConnection providerConnection) w System.Data.Entity.Internal.LazyInternalContext.CreateModel (LazyInternalContext internalContext) w System.Data.Entity.Internal.RetryLazy 2.GetValue(TInput input) at System.Data.Entity.Internal.LazyInternalContext.InitializeContext() at System.Data.Entity.Internal.InternalContext.Initialize() at System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType(Type entityType) at System.Data.Entity.Internal.Linq.InternalSet 1.Initialize() w System.Data.Entity.Internal.Linq.InternalSet 1.GetEnumerator() at System.Data.Entity.Infrastructure.DbQuery 1.System.Collections.Generic.IEnumerable.GetEnumerator() w System.Collections.Generic.List 1..ctor(IEnumerable 1 kolekcji) w System.Linq.Enumerable.ToList [ TSource] (źródło IEnumerable`1) w TestApplication.MainWindow.Window_Loaded (nadawca Object RoutedEventArgs e) D: \ RailwayProjects \ RelayAnalysis \ TestApplication \ MainWindow.xaml.cs: linia 33 InnerException:

+0

Czy możesz wysłać szczegółową wiadomość o 'ModelValidationException', w tym o możliwych wewnętrznych wyjątkach? – Slauma

+0

Zobacz moją EDYTĘ dla wyjątku – Jatin

Odpowiedz

8

Myślę, że foreignKey powinien być Id, a nie StandardRack_id. Należy również użyć wirtualnego, aby móc korzystać z leniwego ładowania.

Działa to dla mnie

using System.ComponentModel.DataAnnotations; 
using System.Data.Entity; 

namespace Racks 
{ 

    public class StandardRack 
    { 
     public int Id { get; set; } 
     public virtual StandardRelay StandardRelay { get; set; } 
    } 

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

     public int StandardRack_Id { get; set; } 

     [ForeignKey("Id")] 
     [Required] 
     public virtual StandardRack StandardRack { get; set; } 
    } 

    public class Context : DbContext 
    { 
     static Context() 
     { 
      Database.SetInitializer<Context>(null); 
     } 

     public DbSet<StandardRack> StandardRacks { get; set; } 
     public DbSet<StandardRelay> StandardRelays { get; set; } 

    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      var context = new Context(); 
      context.Database.Delete(); 
      context.Database.Create(); 

      var standardRack = new StandardRack(); 
      standardRack.StandardRelay = new StandardRelay(); 

      context.StandardRacks.Add(standardRack); 
      context.SaveChanges(); 
     } 
    } 
} 
+0

Arialdo, @Slauma, podejścia zaproponowane przez oboje skutkują tą samą strukturą bazy danych, mianowicie kolumna Id StandardRack służy jako cel klucza obcego (Id) StandardRelay. Pójdę z podejściem Arialdo i zaznaczę jego odpowiedź jako poprawną, chociaż obie odpowiedzi działają. – Jatin

+0

+1 Dobry pomysł! Nie spodziewałem się, że mapowanie jeden-do-jednego będzie również działało z adnotacjami. Zastanawiam się, czy to też działa, jeśli całkowicie usuniesz atrybut "[KeyKey]" (ale pozostawisz atrybut "[Wymagany]" w miejscu). Sprawdziłeś to? – Slauma

+1

@Slauma, Nawet jeśli usunę ten klucz obcy, działa i tworzy tę samą strukturę bazy danych. Więc Foreignkey można całkowicie pominąć.Bardzo dziękuję wam za pomoc. – Jatin

23

Jeden -to-one asocjacje kluczy obcych nie są obsługiwane przez Entitiy Framework. Musisz usunąć klucz obcy i używać współdzielonych kluczy podstawowych (klucz podstawowy z zależny jest jego klucz obcy do dyrektora w tym samym czasie):

public class StandardRack { 
    public int Id {get;set} 
    public StandardRelay StandardRelay {get;set} 
} 

public class StandardRelay { 
    public int Id {get;set} 
    public StandardRack StandardRack { get; set; } 
} 

Mapowanie w Fluent API:

modelBuilder.Entity<StandardRack>() 
    .HasOptional(rack => rack.StandardRelay) 
    .WithRequired(relay => relay.StandardRack); 

(Usprawiedliwiam tutaj, że StandardRack ma opcjonalny przekaźnik.)

+0

Osobiście wolę takie podejście do tego, które napisałem powyżej: Lubię jednostki agnostyczne, dlatego zawsze staram się unikać adnotacji. +1 –

+2

Pamiętaj też: aby użyć leniwego ładowania, dodaj "wirtualne" do nieprymitywnych właściwości. –

+0

Nie obsługiwany przez Entity Framework, czy przede wszystkim przez Code First? Na pewno działa to w edmx. –

3

Oto jak można określić jeden-na-jeden związek z FK użyciu biegle API.

Należy zauważyć, że FK nie jest jawnie zdefiniowany w Enitity, ale jest zdefiniowany za pomocą płynnego API.

public class StandardRack { 
    public int Id {get;set} 
    public StandardRelay StandardRelay {get;set} 
} 

public class StandardRelay { 
    public int Id {get;set} 
    public StandardRack StandardRack { get; set; } 
} 


modelBuilder.Entity<StandardRack>() 
      .HasOptional(x => x.StandardRelay) 
      .WithOptionalPrincipal(y => y.StandardRack) 
      .Map(configurationAction: new Action<ForeignKeyAssociationMappingConfiguration>(x => x.MapKey("StandardRack_Id"))); 

biegle API doda kolumnę StandardRack_Id w StandardRelay.

Należy pamiętać, że nazwa metody WithOptionalPrincipal() jest dość ironiczna. Dokumentacja msdn z WithOptionalDependent powinna to wyjaśnić.

+0

Nikt nigdy nie wspomniał o '.Map' i' .MapKey', dziękuję za opublikowanie tego! – Langdon

+0

Dzięki, mój czas oszczędzać! :-) – VikciaR

Powiązane problemy