簡體   English   中英

如何遍歷MultiSelectList發布的值並將每個值插入ASP.Net MVC 5中的新數據庫行中?

[英]How to loop through MultiSelectList posted values and insert each into a new database row in ASP.Net MVC 5?

我已經訪問了所有可以找到的搜索結果,但被卡住了。

我正在使用ASP.Net MVC 5在“ DVD商店”網站上工作,在將MultiSelectList值插入數據庫中時遇到了一些困難。 該數據庫結構具有一個多對多表,該表存儲電影ID,流派ID和主鍵。 還有一個電影表,其中包含諸如電影標題,成本,圖像路徑,導演,評分等字段。

我的插入邏輯可以將數據放入電影表中,但是在“創建”視圖中有一個多選列表,該列表是從數據庫中的電影流派列表中填充的。 當我選擇一個列表項時,ID會很好地插入到moviegenre表中。 當我選擇多個時,僅插入一個ID。 我想為每個選擇插入一個新行,並帶有電影ID和流派ID(即,如果選擇了3個流派,請為每個行創建3個具有相同電影ID但流派ID不同的新行)。

如何遍歷已發布的MultiSelectList數據並為每個值插入新行?

這是我視圖中的代碼:

@Html.ListBoxFor(r => r.CMovie.GenreId, new MultiSelectList(Model.CGenreList, "Id", "Description"), new { @class = "form-control" })

我的控制器:

[HttpPost]
    public ActionResult Create(MovieGenresDirectorsRatings mgdr) // The ViewModel
    {
        try
        {
            mgdr.CMovie.Insert();
            return RedirectToAction("Index");
        }
        catch (Exception ex)
        {
            throw ex;
            return View(mgdr);
        }
    }

ViewModel:

public class MovieGenresDirectorsRatings
{
    public IEnumerable<int> GenreId { get; set; }
    public CGenreList CGenreList { get; set; }
    public CDirectorList CDirectorList{ get; set; }
    public CFormatList CFormatList { get; set; }
    public CRatingList CRatingList { get; set; }
    public CGenre CGenre { get; set; }
    public CMovie CMovie { get; set; }        
}

我在模型中的插入邏輯:

public void Insert()
    {
        using (myEntities dc = new myEntities())
        {
            try
            {        
                tblMovie movie = new tblMovie();

                // Add movie to tblMovie
                movie.Id = 1;
                if (dc.tblMovies.Any()) 
                    movie.Id = dc.tblMovies.Max(p => p.Id) + 1;

                this.Id = movie.Id;
                movie.Title = this.Title;
                movie.Description = this.Description;
                movie.ImagePath = this.ImagePath;
                movie.Cost = this.Cost;
                movie.RatingId = this.RatingId;
                movie.FormatId = this.FormatId;
                movie.DirectorId = this.DirectorId;

                try
                {
                    tblMovieGenre genre = new tblMovieGenre();
                    genre.Id = 1;
                    if (dc.tblMovieGenres.Any())
                        genre.Id = dc.tblMovieGenres.Max(p => p.Id) + 1; 

                    // THIS IS THE PART that I'm struggling with. 
                    // I think the data is there, I'm just not sure how to access it
                    foreach (var GenreId in GenreId) // This line is probably wrong, but I'm not sure how to access the data
                    {
                        genre.GenreId = this.GenreId.FirstOrDefault();
                        genre.MovieId = movie.Id;
                        dc.tblMovieGenres.Add(genre);
                    }
                }
                catch (Exception ex)
                {
                    throw ex;
                }

                dc.tblMovies.Add(movie);

                // Commit changes
                dc.SaveChanges();


            }
            catch (Exception ex)
            { 
                throw ex;
            }
        }
    }

我已經嘗試過foreach循環和for循環,但無法正常工作。 我究竟做錯了什么?


編輯#1:進行一些更改后,這是CMovie類中我(當前的和無效的)完整的Insert邏輯。 當我從MultiSelectList中僅選擇一個“流派”時,它可以正常工作並正確插入兩個表中。 但是,當我從MultiSelectList中選擇兩個或多個“流派”時,出現“值不能為空,參數名稱:項目”錯誤。

public void Insert()
{
    using (dbEntities2 oDc = new dbEntities2())
    {
        try
        {        
            tblMovie movie = new tblMovie();
            // Add movie to tblMovie
            movie.Id = 1;
            if (oDc.tblMovies.Any()) // If table is not empty
                movie.Id = oDc.tblMovies.Max(p => p.Id) + 1;
                this.Id = movie.Id;
                movie.Title = this.Title;
                movie.Description = this.Description;
                movie.ImagePath = this.ImagePath;
                movie.Cost = this.Cost;
                movie.RatingId = this.RatingId;
                movie.FormatId = this.FormatId;
                movie.DirectorId = this.DirectorId;

                try
                {
                    foreach (var GenreId in GenreIds)
                    {
                        tblMovieGenre genre = new tblMovieGenre();
                        genre.Id = 1;
                        if (oDc.tblMovieGenres.Any())
                        {
                            genre.Id = oDc.tblMovieGenres.Max(p => p.Id) + 1; // genre.Id is set to the highest id in the table, +1
                        }
                        genre.Id = this.Id;
                        genre.GenreId = GenreId;
                        genre.MovieId = movie.Id;
                        oDc.tblMovieGenres.Add(genre);
                    }
                }
                catch (Exception ex)
                {
                    throw ex;
                }

                oDc.tblMovies.Add(movie);

                // Commit changes
                oDc.SaveChanges();


            }
            catch (Exception ex)
            { 
                throw ex;
            }
        }
    }
}`

編輯2:我找到了解決問題的方法。 希望這可以幫助其他遇到相同問題的人。 我將創建更改為使用下拉列表而不是多重選擇列表,並修改了edit方法以允許更新多個流派。

CMovie模型內部,我創建了兩個新方法, AddGenreDeleteGenre 在控制器中,我添加了四個新的IEnumberable<int>變量:oldGenreIds,newGenreIds,添加和刪除。

然后,我從IEnumerable刪除和添加列表:

IEnumerable<int> deletes = oldGenreIds.Except(newGenreIds);

IEnumerable<int> adds = newGenreIds.Except(oldGenreIds);

deletes.ToList().Foreach(a => mgdr.CMovie.DeleteGenre(id, a));

adds.ToList().Foreach(a => mgdr.CMovie.AddGenre(id, a));

然后調用update方法,該方法設置更改的值(包括電影標題,描述,圖像路徑等):

mgdr.CMovie.Update();

通過將ForEach邏輯移到控制器中,我可以多次調用AddGenre方法-當直接在Insert方法中調用它時,我無法執行此操作。

您的post方法應該接受數組,而不是單個對象。

[HttpPost]
public ActionResult Create(MovieGenresDirectorsRatings[] mgdr) // The ViewModel
{
    foreach(var genr in mgdr){
          try
          {
              genr.CMovie.Insert(); //inserting each object received from view. 
              return RedirectToAction("Index");
          }
          catch (Exception ex)
          {
              throw ex;
              return View(mgdr);
          }
    }
}

這個想法是從視圖中接收所有對象。 即使您的視圖正在發布多選列表中的所有項目,您也需要在控制器中使用類似數組的結構來從視圖中獲取數據。 將數據放入控制器后,就可以循環遍歷所有這些數據,並一一插入。

這里是問題(實際上是一個忽略):

 tblMovieGenre genre = new tblMovieGenre();
 // code...
 foreach (var GenreId in GenreId)
 {
     genre.GenreId = this.GenreId.FirstOrDefault();
     // code
     dc.tblMovieGenres.Add(genre);
 }

因此,請參見上面的代碼,創建一個tblMovieGenre ,然后在循環中不斷tblMovieGenres添加相同的tblMovieGenres實例。 因此,從本質tblMovieGenres ,您需要添加一個tblMovieGenres其中包含循環中上次迭代的值。

固定

要解決此問題,請在循環內移動實例化:

 foreach (var GenreId in GenreId)
 {
     tblMovieGenre genre = new tblMovieGenre();
     // code...
     dc.tblMovieGenres.Add(genre);
  }

其他建議

1

.NET中不鼓勵使用匈牙利表示法,因此,在數據庫表中添加tbl前綴不僅是一種表示法問題,而且會使您的代碼更難以閱讀,尤其是在使用ORM時。 因此,如果從表名中刪除tbl ,則代碼將是:

MovieGenere而不是tblMovieGenre

2

另外,如果我看一行代碼,並且可以弄清楚對象的類型,那么我總是使用var來代替。 像這樣:

tblMovieGenre genre = new tblMovieGenre();
var genre = new tblMovieGenre();

那是個人喜好(減少打字)。

但是,如果我無法通過讀取單行來弄清類型,那么我就不要使用var

tblMovieGenre genre = GetMovie();

3

如果使表的主鍵列identity列從1開始,那么您將不需要這樣的代碼:

movie.Id = 1;
if (dc.tblMovies.Any()) 
    movie.Id = dc.tblMovies.Max(p => p.Id) + 1;

每當您在代碼中創建一個新對象時,它的ID都為0,並將其添加到數據庫中時,EF會將其視為新記錄,並為其生成新的標識。 這將使您遠離您管理ID的責任,這意味着更少的編碼。

暫無
暫無

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

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