2016-10-04 58 views
2

我正在從Books表中加載書籍的IQueryable,還有另一個名爲BookLoans的表。我有一個DateTime?屬性在我的ViewModel命名爲可用性。我試圖找出在我的select語句中基本出去的最佳方法,並查看當前Book的BookID是否出現在BookLoans表中的記錄中,以及DateTime是否出現?名爲ReturnedWhen的變量在該記錄中也是NULL。我基本上試圖將本書標記爲可用,或者在填充IQueryable時將其選中。在LINQ聲明中檢查第二個表中的值

有人建議我儘可能將這一切都當作一個LINQ語句,但我試圖弄清楚如果像下面那樣填充書籍然後通過foreach循環運行它會更容易嗎?也有人建議加入會工作,但我真的只是想找出最好的方法,然後如何去實際做到這一點。

var books = 
_context.Books 
.Select(r => new BookIndexViewModel 
{ 
    BookID = r.BookID, 
    Title = r.Title, 
    Author = r.Author, 
    ISBN = r.ISBN, 
    GenreName = r.Genre.Name 
}).ToList(); 

Book實體:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Threading.Tasks; 

namespace Open_School_Library.Data.Entities 
{ 
    public class Book 
    { 
     public int BookID { get; set; } 
     public string Title { get; set; } 
     public string SubTitle { get; set; } 
     public string Author { get; set; } 
     public int GenreID { get; set; } 
     public int DeweyID { get; set; } 
     public int ISBN { get; set; } 

     public Genre Genre { get; set; } 
     public Dewey Dewey { get; set; } 
     public virtual BookLoan BookLoan { get; set; } 
    } 
} 

BookLoan實體:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Threading.Tasks; 

namespace Open_School_Library.Data.Entities 
{ 
    public class BookLoan 
    { 
     public int BookLoanID { get; set; } 
     public int BookID { get; set; } 
     public int StudentID { get; set; } 
     public DateTime CheckedOutWhen { get; set; } 
     public DateTime DueWhen { get; set; } 
     public DateTime? ReturnedWhen { get; set; } 

     public Book Book { get; set; } 
     public Student Student { get; set; } 
    } 
} 

BookIndexViewModel:

using System; 
using System.Collections.Generic; 
using System.ComponentModel.DataAnnotations; 
using System.Linq; 
using System.Threading.Tasks; 

namespace Open_School_Library.Models.BookViewModels 
{ 
    public class BookIndexViewModel 
    { 
     public int BookID { get; set; } 
     public string Title { get; set; } 
     [Display(Name = "Author")] 
     public string Author { get; set; } 
     [Display(Name = "Genre")] 
     public string GenreName { get; set; } 
     public int ISBN { get; set; } 
     public string BookLoan { get; set; } 
     public DateTime? Availability { get; set; } 
    } 
} 

回答

1

這裏是你的類

的一些精簡版本
public class Book { 
    public int BookId { get; set; } 
    public string Title { get; set; } 
} 

public class BookLoan { 
    public int BookId { get; set; } 
    public DateTime CheckedOutOn { get; set; } 
    public DateTime? ReturnedOn { get; set; } 
    public DateTime DueOn { get; set; } 
} 

public class BookViewModel { 
    public int BookId { get; set; } 
    public string Title { get; set; } 
    public bool IsAvailable { get; set; } 
    public DateTime? AvailableOn { get; set; } 
} 

然後我們可以做兩件事情讓你要找的視圖模型列表:

  1. 只看借書其中ReturnedOn爲空
  2. 使用DefaultIfEmpty做左外連接見https://msdn.microsoft.com/en-us/library/bb397895.aspx

所以你最終每本書一個項目,只有loanWithDefault如果這本書目前已簽出。

var viewModel = from book in books 
      join loan in loans.Where(x => !x.ReturnedOn.HasValue) on book.BookId equals loan.BookId into result 
      from loanWithDefault in result.DefaultIfEmpty() 
      select new BookViewModel { 
       BookId = book.BookId, 
       Title = book.Title, 
       IsAvailable = loanWithDefault == null, 
       AvailableOn = loanWithDefault == null ? (DateTime?) null : loanWithDefault.DueOn 
      }; 

這裏是一個工作示例:https://dotnetfiddle.net/NZc2Xd

這裏是LINQ查詢的細分:

  1. from book in books是你從
  2. loans.Where(x => !x.ReturnedOn.HasValue)選擇第一個表限制貸款每本書最多一件物品(以及我們在這種情況下關心的貸款)
  3. join loan in loans on book.BookId equals loan.BookId into result i我們加入貸款表,這樣我們就可以將其作爲我們結果集的一部分。加入條件是書的BookId等於貸款的BookId
  4. from loanWithDefault in result.DefaultIfEmpty()基本上使貸款加入「左外連接」。這意味着即使沒有貸款還沒有退還這本書,你會得到你的結果集中的書。否則,你只會得到不可用的書籍。請參閱此Stack Overflow answer以獲得有關不同連接的良好解釋。另請參閱https://msdn.microsoft.com/en-us/library/bb397895.aspx瞭解如何使用LINQ進行左外連接。
  5. 最後,您從可用的Book和BookLoan對象中選擇您的視圖模型。

下面是一個類似原始的SQL查詢會是什麼樣

select 
    Book.BookId, 
    Book.BookTitle, 
    BookLoan.DueOn 
from 
    Book 
    left outer join BookLoan on 
    Book.BookId = BookLoan.BookId 
    and BookLoan.ReturnedOn is null 
+0

我得到它和工作,但我不會說謊,我不完全瞭解情況,在LINQ聲明,我是想知道你是否可以爲我分手? –

+1

@ChristopherJohnson查看我添加到答案的細目,並告訴我這是否有幫助。 LINQ查詢可能會變得非常複雜,難以閱讀。 –

+0

它奇妙地工作。我想知道我需要做什麼才能使這項工作適用於單個查詢?我希望在Details視圖上重複使用或者修改這個,我一直使用'.FirstOrDefault()'以及用'Where whatever.BookId == id'過濾。 –