簡體   English   中英

ASP.NET MVC CORE - 多對多關系 - 創建視圖

[英]ASP.NET MVC CORE - Many to many relations - Create Views

因此,我遇到了兩個實體之間存在多對多關系的情況。 在中間,有一些字段可以描述關系。 我將通過以下示例簡化情況(粗體表示兩個實體之間的簡單字段:

public class Hobby
{
    public int HobbyID                            {get;set;}
    public string Name                            {get;set;}
    public string Type                            {get;set;}
    public ICollection<PersonHobby> PersonHobbies {get;set;}
}

public class Person
{
    public int PersonID                           {get;set;}
    public int Age                                {get;set;}
    public string Name                            {get;set;}
    public ICollection<PersonHobby> PersonHobbies {get;set;}
}

public class PersonHobby
{
    public int PersonHobbyID                      {get;set;}
    public int PersonID                           {get;set;}
    public int HobbyID                            {get;set;}
    **public int Rating                             {get;set;}**
}

我的目標是什么? 有一個創建表單,它可以讓我創建一個人並立即將評級歸因於一個或多個愛好。 創建表單應顯示所有可用愛好的輸入字段,但在提交時,應僅存儲包含數據的字段。

我需要幫助來了解實現這一目標的最佳方法。 到目前為止,我嘗試了 Person Create View 和 Controller 以顯示表單中的所有愛好。 我這樣做的方法是在創建 controller 時加載所有愛好並將它們初始化為空。 但是在提交時,我收到了如下錯誤:“模型綁定的復雜類型不能是抽象類型或值類型,並且必須有一個無參數的構造函數。”

謝謝你。

開始的一點建議:我會在您的視圖中使用視圖模型而不是實體類,因為它會為您提供更大的靈活性並幫助您實現目標,而不會開始使用不屬於那里的代碼弄臟您的視圖。 顯然,你可以用你的實體類來做,盡管提供一些改變,但我不推薦它。

我相信你得到的錯誤是,因為你試圖綁定到定義ICollection屬性的實體類,並且 model 綁定器無法確定應該用於實例化它們的具體類型。 例如,為了快速修復,您可以使用具體類型(例如CollectionList )更改您的ICollection 但同樣,這是我的第一個建議......

所以,要以正確的方式做到這一點,這就是我要做的:

public class PersonViewModel
{
   public int Age {get;set;}
   public string Name {get;set;}
   public List<HobbyViewModel> Hobbies {get;set;}
}

public class HobbyViewModel
{
  public int HobbyID {get;set;}
  public string Name {get;set;}
  public string Type {get;set;}
  public int? Rating {get;set;}
}

public class PersonController
   : Controller
{
   ...

   [HttpGet]
   public IActionResult Create()
   {
      PersonViewModel viewModel = new PersonViewModel();
      viewModel.Hobbies = this.DbContext.Hobbies.Select(h => new HobbyViewModel() { Name = h.Name, Type = h.Type }).ToList();
      return this.View(viewModel);
   }

   [HttpPost]
   public IActionResult Create(PersonViewModel model)
   {
      if(!this.ModelState.IsValid)
         return this.BadRequest(model);
      Person person = new Person(){ Age = model.Age, Name = model.Name };
      foreach(HobbyViewModel hobbyViewModel in model.Hobbies)
      {
        //Check if the user has rated the hobby and if not, skip it
        if(!hobbyViewModel.Rating.HasValue)
          continue;
        person.PersonHobbies.Add(new PersonHobby(){ HobbyId = hobbyViewModel.HobbyId, Rating = hobbyViewModel.Rating.Value });
      }
      this.DbContext.Persons.Add(person);
      this.DbContext.SaveChanges();
      return this.RedirectToAction(nameof(Index));
   }
}

換句話說,在您的個人表單中,為視圖 model 中提供的每個愛好顯示一個表單,並帶有評級輸入。 當用戶發布表單時,檢查所有提供的愛好以檢查用戶是否已對其進行評分(即:檢查是否設置了可為空的 Rating 屬性),如果已設置,則將新的 PersonHobby 添加到生成的 Person 實體。 瞧!

最后,關於您的實體模型的一些建議:

  • 忘記繁瑣的PersonHobbies屬性名稱。 它不是無處不在的,你應該盡可能地以無處不在為目標:它使你的代碼更漂亮,更容易理解,因此更容易維護。 例如,為 Person 實體命名您的屬性 Hobbies,為 Hobby 實體命名 Persons 或 Voters。
  • 將您的關鍵屬性重命名為 Id,因為它將被 EntityFramework 自動拾取為關鍵屬性,沒有配置和/或數據注釋。 此外,我希望 Person 的 Id 屬性是......好吧,Person 的 id。 無需指定它。
  • 我堅持,為了讓你的生活更輕松,忘記在視圖中使用你的實體類型,或者最糟糕的是,作為 Json/Xml 返回類型。 您應該為您的視圖使用視圖模型,為您的 Json/Xml 返回類型使用數據傳輸對象 (DTO)。 即使這個概念在 go 看來似乎違反了 KISS 原則,相信我,事實並非如此。 隨着時間的推移,它只會簡化你的生活,盡管它在開始時可能看起來毫無意義。 事實上,您的實體類型可能會隨着時間的推移而演變,而您的視圖可能不會,反之亦然。 此外,您的視圖通常需要比您的實體類型更多或不同的信息,並且保持此路徑,您可能會發現自己開始通過調用等來檢查您的視圖,而它應該只包含視圖邏輯。 應該在您的控制器操作中進行調用,並且這些操作應該使用您的視圖所需的所有數據/信息填充模型。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM