我正在从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; }
}
}
答案 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; }
}
然后我们可以做两件事来获得您正在寻找的视图模型列表:
ReturnedOn
为空的图书贷款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查询的细分:
from book in books
是您从loans.Where(x => !x.ReturnedOn.HasValue)
将贷款限制为每本书最多一件(以及我们在这种情况下关心的贷款)join loan in loans on book.BookId equals loan.BookId into result
正在加入贷款表,以便我们将其作为结果集的一部分。连接条件是本书的BookId等于贷款的BookId from loanWithDefault in result.DefaultIfEmpty()
基本上是贷款加入"左外连接"。这意味着,即使本书尚未退还任何贷款,您也会在结果集中获得该书。否则,您只会获得不可用的书籍。有关不同联接的详细说明,请参阅此Stack Overflow answer。另外,请参阅https://msdn.microsoft.com/en-us/library/bb397895.aspx了解如何使用LINQ进行左外连接。这是类似的原始SQL查询的样子
select
Book.BookId,
Book.BookTitle,
BookLoan.DueOn
from
Book
left outer join BookLoan on
Book.BookId = BookLoan.BookId
and BookLoan.ReturnedOn is null