/ / Zapisywanie encji za pomocą klucza obcego w ASP.NET MVC - asp.net-mvc, entity-framework-ctp5, modelstate

Zapisywanie encji za pomocą klucza obcego w ASP.NET MVC - asp.net-mvc, entity-framework-ctp5, modelstate

Potrzebuję pomocy w robieniu czegoś, co zakładam jest proste. Używam ASP.net MVC 3 z CodeFirst (CTP5)

Mam dwa podmioty: Firma i Lokalizacja. Firma może mieć wiele lokalizacji. Klasy są następujące (pozbawione wszelkich niepotrzebnych informacji)

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

[Required]
public string Name { get; set; }

public virtual ICollection<Location> Locations { get; set; }
}

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

[Required]
public string Name { get; set; }

[Required]
public virtual Company Company { get; set; }

}

Teraz w moim kontrolerze pozwalam tylko na tworzenieLokalizacja w kontekście firmy, więc identyfikator firmy jest zawsze przekazywany (w widoku wyświetla nazwę firmy w polu tylko do odczytu, ale nie zezwalaj użytkownikowi na jej zmianę / edycję.

    public ActionResult Create(int companyId)
{
Company company = _session.Single<Company>(c => c.Id == companyId);
Location newLocation = new Location {Company = company};
return View(newLocation);
}

[HttpPost]
public ActionResult Create(Location location)
{
if (ModelState.IsValid)
{
_session.Add<Location>(location);
_session.CommitChanges();
return RedirectToAction("Index");
} else {
return View(location);
}
}

Teraz, gdy próbuję utworzyć nową lokalizację,ModelState.IsValid jest zawsze fałszywa z powodu faktu, że location.Company.Name nie jest dostarczany i jest polem wymaganym w firmie. Nigdy nie próbuję stworzyć tutaj nowej firmy, staram się tylko stworzyć lokalizację z odniesieniem do właściwej firmy. Nie chcę dodawać właściwości Name do widoku tylko po to, aby sprawdzić stan ModelState. Jak można to łatwo osiągnąć? Czy powinienem przekazać coś innego niż widok lub widok?

Odpowiedzi:

2 dla odpowiedzi № 1

Jak wyjaśniłem w swoim komentarzu, potknąłem siępo niewielkiej zmianie, która czyni tę pracę, nadal uważam, że jest to kundel, ponieważ nie rozumiem, dlaczego muszę duplikować element potomny Id, ale najlepszy / najprostszy, jaki mogłem znaleźć, powinien być łatwy do zaktualizowania w przyszłości i będę bądź pierwszy, który przyzna, że ​​nie znam wszystkich (lub większości) tego, co jest w CodeFirst.

Zmieniłem klasę lokalizacji z:

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

[Required]
public string Name { get; set; }

[Required]
public virtual Company Company { get; set; }
}

Do:

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

[Required]
public string Name { get; set; }

[Required]
public int CompanyId { get; set; }
public virtual Company Company { get; set; }
}

Teraz, o ile mogę powiedzieć, to nie zmieniłoschematu bazy danych, ale teraz jedyną rzeczą wymaganą w Lokalizacji (podczas sprawdzania poprawności) jest to, że w polu CompanyId znajduje się identyfikator, właściwość firmy może pozostać pusta (wcześniej próbowano sprawdzić poprawność firmy, ponieważ wymagana była klasa przedsiębiorstwa).

Tak więc teraz, gdy tworzysz Lokalizację, jedyną rzeczą, którą widok musi powrócić w CompanyId.

Ktoś widzi jakieś wady? czy lepszy sposób?


1 dla odpowiedzi nr 2

Możesz łatwo po prostu dodać ukryte pole z nazwą firmy na twoim form. Jego dane zostaną pobrane i wysłane do Twojego działania POST zgodnie z oczekiwaniami.

Jeśli nie używasz nazwy firmy po stronie serweraw ogóle możesz wypełnić to ukryte pole dowolnym tekstem fikcyjnym, o ile identyfikator firmy jest poprawny (ponieważ go używasz). Ale jeśli potrzebujesz poprawnej nazwy firmy z twoim ID, będziesz musiał wypełnić rzeczywistą nazwę w ukrytym polu zamiast jakiegoś fałszywego tekstu.

Tak czy inaczej. Spowoduje to dodanie ukrytego pola dla nazwy Twojej firmy

<%= Html.HiddenFor(m => m.Company.Name) %>

a jeśli nie masz właściwości firmy, która jest ustawiona na cokolwiek, to możesz równie dobrze wykorzystać to:

<%= Html.Hidden("Company.Name", "Super duper company") %>

Niezależnie od tego, czy ta wartość jest rzeczywistą nazwą czy fałszywą nazwą, nie ma to znaczenia. Twój model będzie ważny na poczcie zwrotnej.

Regularne ogłaszanie zwrotne lub Ajax?

Przypuszczam, że używasz zwykłego odświeżenia, a nie odświeżenia Ajax. Jeśli używasz Ajaxa i używasz jQuery i wywołujesz $.post() lub $.ajax() lub coś podobnego, zawsze możesz podać obiekt, który Ci się podoba. Możesz wpisać dowolną wartość nazwy firmy w swoim kodzie JavaScript.

Jeśli masz złożone obiekty w JavaScript i chcesz je wysłać do akcji kontrolera z silnymi parametrami typu (tak, że będą sprawdzane), możesz użyć ta mała wtyczka jQuery mój, który przygotowuje każdy obiekt JSON, aby poprawnie wysłać go do akcji Asp.net MVC, więc dane będą automatycznie wiązane z twoimi silnymi typami, aby uzyskać walidację. Czy JavaScript również się pojawia. :)

Dodatkowe informacje

Ponieważ wskazałeś (w komentarzu), że twoje podmioty są bardzo pracujące w toku i możesz dodawać / usuwać wymagane pola, może to być bardzo uciążliwe, aby zmienić wszystkie powiązane widoki.

Są jednak sposoby, które możesz podjąć, aby twoje życie było nieco łatwiejsze, jeśli chodzi o zmienne modele i różne scenariusze walidacji w zależności od stanu obiektu:

  1. Mają oddzielne modele widoku do procesu tworzenia, które obejmują również funkcję automatycznego przekonwertowania na klasę modelu aplikacji:

    public class LocationCreate
    {
    public int Id { get; set; }
    
    [Required]
    public string Name { get; set; }
    
    [Required]
    public int CompanyId { get; set; }
    
    public Location ToModelInstance()
    {
    return new Location {
    Id = this.Id,
    Name = this.Name,
    Company = new Company {
    Id = this.CompanyId,
    Name = "Super duper company Ltd." // you can as well omit this line
    }
    };
    }
    }
    
  2. Użyj dziedziczenia:

    public class CompanyBase
    {
    public int Id { get; set; }
    }
    
    public class Company : CompanyBase
    {
    [Required]
    public string Name { get; set; }
    
    public virtual ICollection<Location> Locations { get; set; }
    }
    
    public class Location
    {
    public int Id { get; set; }
    
    [Required]
    public string Name { get; set; }
    
    [Required]
    public virtual CompanyBase Company { get; set; }
    
    }