2013-08-02 13 views
6

Używam Entity Framework 5 i MVC 4, z .NET 4.5 przy użyciu migracji First Code. Posiadam klucze obce między dwiema jednostkami w relacji 1 do zera lub 1. Kiedy staram się stworzyć płytę dla Joggera, wszystko się wysadza. Otrzymuję komunikaty o błędach, które są albo:Przypisywanie identyfikatora użytkownika do klucza obcego = null

  • klucz obcy jest zerowy odniesienia
  • dbo.Jogger nie istnieje
  • nieobsługiwany wyjątek ... bez metadanych.

Po uruchomieniu przeglądarki EF, relacje nawigacji są doskonałe. W tej chwili nie jest używany żaden kod Fluent API.

Class User

 [Key] 
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)] 
    public int UserId { get; set; } 
    public string UserName { get; set; } 

    // Other properties 

    public int? JoggerId { get; set; } 
    public virtual Jogger Jogger { get; set; } 

Jogger Klasa

[ForeignKey("UserId")] 
    public int JoggerId { get; set; } 

    public virtual UserProfile UserId { get; set; } 

Gdy JoggerController są generowane go produkuje ten kod dla uzyskania i Metod Post:

// GET: /Jogger/Create 

    public ActionResult Create() 
    { 
     ViewBag.JoggerId = new SelectList(db.UserProfiles, "UserId", "UserName"); 
     return View(); 
    } 

    // 
    // POST: /Jogger/Create 

    [HttpPost] 
    [ValidateAntiForgeryToken] 
    public ActionResult Create(Jogger jogger) 
    { 



     if (ModelState.IsValid) 
     { 
      db.Jogger.Add(jogger); 
      db.SaveChanges(); 
      return RedirectToAction("Index"); 
     } 

     ViewBag.JoggerId = new SelectList(db.UserProfiles, "UserId", "UserName", jogger.JoggerId); 
     return View(jogger); 
    } 

W widoku Jogger/Create nie ma pól dla JoggerId lub UserId zgodnie z wygenerowanym kodem.

Zazwyczaj kończy się niepowodzeniem w części kodu (ModelState.IsValid), w której wynik wskazuje wartość JoggerId = 0 i UserId = null.

Nie widziałem tego zachowania na tutorialu Uniwersytetu Contoso na stronie internetowej asp.net i przyjrzałem się także witrynie MSDN Learn EF. Nie mogę rozwiązać tego problemu. Twoja rada jest doceniana.

Odpowiedz

3

Po wielu prób i błędów znalazłem sposób, który działa na przypisać Klucz obcy wartość.

Po pierwsze, moje relacje zostały skonfigurowane niepoprawnie: UserProfile Class nie potrzebuje publicznego int? GolferId do reprezentowania właściwości nawigacji. Klasy końcowe wyglądały następująco:

UserProfile

[Key] 
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)] 
    public int UserId { get; set; } 
    public string UserName { get; set; } 

    // Navigation properties 
    public virtual Jogger Jogger { get; set; } 

Jogger Class

[Key] 
[ForeignKey("UserId")] 
public int JoggerId { get; set; } 

public string Pronation {get; set;} 

public virtual UserProfile UserId { get; set; } 

Taka konfiguracja poprawna relacja bez konieczności jakiegokolwiek kodu Fluent API.

Przypisanie wartości ForeignKey było nieco trudniejsze i jestem pewien, że jest DUŻO lepszych sposobów na zrobienie tego niż to.

  1. Zamiast innej metody definiowania rusztowania (id = 0) użyłem FormCollection. Możesz także użyć [Bind (Include = "field1, field2, field3")], aby upewnić się, że wysyłane są prawidłowe pola.
  2. Istnieje długa droga dotarcia do id_uzytkownika zalogowany użytkownik, który korzysta z User.Identity.Name
  3. FormCollection pozwala mi odniesienia i zapisać na przykład inne pola Pronacji

    [HttpPost] 
    [ValidateAntiForgeryToken] 
    public ActionResult Create(FormCollection values) 
    { 
    
        var jogger = new Jogger(); 
        TryUpdateModel(jogger); 
    
        var context = new TestContext(); 
        var userqq = User.Identity.Name; 
        var user = context.UserProfiles.SingleOrDefault(u => u.UserName == userqq); 
    
        if (ModelState.IsValid) 
        { 
    
          jogger.JoggerId = user.UserId; 
          jogger.Pronation = values["Pronation"]; 
    
    
          db.Joggers.Add(jogger); 
          db.SaveChanges(); 
          return View(); 
    
    
        } 
         ViewBag.JoggerId = new SelectList(db.UserProfiles, "UserId", "UserName", jogger.JoggerId); 
         return View(jogger); 
    
    } 
    

To nie było całkiem w ogóle, ale to nie działa. Dzięki @Moeri za skierowanie mnie we właściwym kierunku.

1

Oto twój błąd:

public virtual UserProfile UserId { get; set; } 

Entity Framework Code First współpracuje z konwencjami, jednym z nich jest nazwa konwencje oparte. Oznacza to, że jeśli masz właściwość "UserId", będzie ona szukała tabeli "Użytkownik" i skonfigurowała ją jako klucz obcy dla tej tabeli. Myślę, że to wysadzenie w powietrze, ponieważ nadałeś swojej właściwości nawigacji nazwę, która jest tradycyjnie używana dla własności klucza obcego.

Prawidłowy sposób pracy byłoby:

public virtual int? UserId { get; set; } 
public virtual User User { get; set; } 

Jeśli chcesz, aby Twoje mieszkanie nazwać „UserProfileId”, trzeba będzie użyć „ForeignKey” atrybut lub biegle konfiguracji składni, aby pozwolić Entity Framework że to jest klucz obcy:

public virtual int? UserProfileId{ get; set; } 

[ForeignKey("UserProfileId") 
public virtual User User { get; set; } 

lub ze składnią płynnym (piszesz to w metodzie OnModelCreating z kontekstu, albo w oddzielnej klasy, która dziedziczy z EntityTypeConfiguration):

HasRequired(j => j.User).WithMany().HasForeignKey(i => i.UserProfileId) 

Edycja: Właśnie zauważyłem, że twoja tabela użytkownika jest rzeczywiście nazywana UserProfile, który to rodzaj renderuje drugą połowę mojej odpowiedzi na dyskusję. Niemniej jednak zostawię go tak, jak jest, ponieważ może być edukacyjny.

+1

Dzięki @Moeri Zrobiłem zmiany, które zasugerowałeś w pierwszej połowie, używając publicznego wirtualnego UserProfile UserProfile), ale nadal dałeś mi ten sam błąd (Model jest prawidłowy). Identyfikator JoggerId jest ustawiony na 0, gdy Add nie powiedzie się. – Springbokkie

+0

Zastanawiam się, czy coś jest wadliwego z moim rozwiązaniem, ponieważ nawet gdy ręcznie wprowadzę wartości bazy danych dla ID użytkownika w tabeli Jogger, nadal zabije model oglądając ręcznie wprowadzony rekord Jogger. – Springbokkie

2

Błąd występuje w modelu bazy danych. Kod struktury jednostki Najpierw zawsze będzie wymagać konfiguracji dla relacji jeden-do-jednego. Kod Pierwszy nie może określić, która klasa jest zależna w takich sytuacjach.

1- W klasie Jogger dodać właściwość:

public virtual User User { get; set; } 

2 - W swojej metodzie OnModelCreating dodać:

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
{ 
     // One to One relationship 
     modelBuilder.Entity<User>() 
         .HasOptional(t => t.Jogger) 
         .WithOptionalDependent(m => m.User); 
} 
+0

Dzięki Aguedo. Próbowałem go zbudować w ten sposób, ale dostałem błąd w przeglądarce EF. Udało mi się znaleźć sposób przypisania JoggerId z UserId. – Springbokkie

Powiązane problemy