检查LINQ语句中第二个表的值

时间:2016-10-04 22:41:32

标签: entity-framework linq ef-code-first

我正在从Books表中加载一个IQueryable书籍,还有另一个名为BookLoans的表。我有一个DateTime?我的ViewModel中的属性名为Availability。我试图找出在我的select语句中基本出去的最佳方法,看看当前的Book BookID是否出现在BookLoans表中的记录中,以及是否有DateTime?名为ReturnedWhen的变量在该记录中也为NULL。当我填充IQueryable时,我基本上试图将该书标记为可用或已经检查过。

有人建议我尝试将这一切都作为一个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();

图书实体:

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 个答案:

答案 0 :(得分: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
  3. 因此,如果图书目前已经过结帐,那么每本书最终会有一个项目,而只有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. 中选择的第一个表格
    3. loans.Where(x => !x.ReturnedOn.HasValue)将贷款限制为每本书最多一件(以及我们在这种情况下关心的贷款)
    4. join loan in loans on book.BookId equals loan.BookId into result正在加入贷款表,以便我们将其作为结果集的一部分。连接条件是本书的BookId等于贷款的BookId
    5. from loanWithDefault in result.DefaultIfEmpty()基本上是贷款加入"左外连接"。这意味着,即使本书尚未退还任何贷款,您也会在结果集中获得该书。否则,您只会获得不可用的书籍。有关不同联接的详细说明,请参阅此Stack Overflow answer。另外,请参阅https://msdn.microsoft.com/en-us/library/bb397895.aspx了解如何使用LINQ进行左外连接。
    6. 最后,从可用的Book和BookLoan对象中选择视图模型。
    7. 这是类似的原始SQL查询的样子

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