簡體   English   中英

LINQ 查詢加入 2 個不同的表

[英]LINQ Query to join 2 different tables

我目前正在從事圖書館管理項目,用戶在借書時會更新他們的閱讀狀態。 當我使用 linq 連接表時,除了狀態之外的所有其他內容都在那里。 這是我的模型: 用戶模型(TblUser):

using Microsoft.AspNetCore.SignalR;
using System;
using System.Collections.Generic;

namespace LibMan.Models.DB
{
    public partial class TblBookStatus
    {
        public int ResId { get; set; }
        public string UserEmail { get; set; }
        public int? BookId { get; set; }
        public string Status { get; set; }

        public virtual TblBook Book { get; set; }
        public virtual TblUser User { get; set; }
    }

}

圖書模型(TblBook):

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;

namespace LibMan.Models.DB
{
    public partial class TblBook
    {
        public int BookId { get; set; }
        public string Title { get; set; }
        public string Author { get; set; }
        public string Translator { get; set; }
        public string Publisher { get; set; }
        public string Description { get; set; }
        public string Category { get; set; }
        public byte[] Cover { get; set; }
    }
}

圖書狀態模型(TblBookStatus):

using Microsoft.AspNetCore.SignalR;
using System;
using System.Collections.Generic;

namespace LibMan.Models.DB
{
    public partial class TblBookStatus
    {
        public int ResId { get; set; }
        public string UserEmail { get; set; }
        public int? BookId { get; set; }
        public string Status { get; set; }

        public virtual TblBook Book { get; set; }
        public virtual TblUser User { get; set; }
    }

}

繼續下面的代碼,您可以看到我使用 linq 查詢連接創建了 DisplayBook,但我無法在 html 端顯示狀態。 它說它

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using LibMan.Models.DB;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Internal;

namespace LibMan.Pages
{
    public class LibraryModel : PageModel
    {
        private readonly LibMan.Models.DB.LibManContext _context;
        public string Message { get; set; }
        public LibraryModel(LibMan.Models.DB.LibManContext context)
        {
            _context = context;
            DisplayBook = new List<TblBook>();
;       }
        public IList<TblBookStatus> TblBookStatus { get; set; }
        public IList<TblBook> TblBook { get; set; }
        public IList<TblBook> DisplayBook { get; set; }
        public IList<TblUser> TblUser{ get; set; }
        [BindProperty]
        public async Task OnGetAsync()
        {
            TblBookStatus = await _context.TblBookStatus.ToListAsync();
            TblBook = await _context.TblBook.ToListAsync();
            TblUser = await _context.TblUser.ToListAsync();
            var UserEmail = HttpContext.Session.GetString("Email");

            if (TblBookStatus != null && TblBook != null)
            {
                DisplayBook = (from book in TblBook
                                join stat in TblBookStatus
                                on book.BookId equals stat.BookId
                                join usr in TblUser
                                on stat.UserEmail equals usr.Email
                                where (usr.Email == UserEmail)
                                select book).ToList();
            }
        }
    }
}

我怎樣才能做到這一點? 我可以在將 DisplayBook 分配給 Linq 查詢結果的語句中執行此操作嗎? 做這個的最好方式是什么? 謝謝:注意。 如果需要,我可以提供 html 代碼。

有多種選擇。 您可以更正將DisplayBook類型更改為 valuetuple 的代碼(或創建單獨的類型以提高可讀性):

 public IList<(TblBook Book, TblBookStatus  Status)> DisplayBook { get; set; }

獲取用戶的書籍和狀態:

TblBookStatus = await _context.TblBookStatus.Include(s => s.User).ToListAsync();
TblBook = await _context.TblBook.ToListAsync();

最后填寫DisplayBook

DisplayBook = TblBook
    .Select(b => (b, TblBookStatus.FirstOrDefault(s => s.BookId == b.BookId)))
    .ToList()

據我從您的評論中了解到,您在狀態和用戶之間存在一對一的關系,所以這樣您就可以獲取圖書館中的所有書籍,並且所有狀態(書籍的狀態可以是null )具有填充的用戶關系。

附言

ToListAsync不應返回 null,因此 null 檢查在那里是多余的。

UPD

要僅獲取有關一個用戶及其書籍的信息,您可以使用單個查詢來完成:

var statusesWithUserAndBooks = await _context.TblBookStatus
    .Include(s => s.User)
    .Include(s => s.Book)
    .Where(s => s.User.Email == UserEmail)
    .ToListAsync();

如果您需要數據子集,則使用必要的字段創建DTO ,如下所示:

public class DisplayBookDTO
{
    public string Status { get; set; }
    public string BookTitle { get; set; }
    public string BookAuthor { get; set; }
}

public IList<DisplayBookDTO> DisplayBook { get; set; }

DisplayBook = await _context.TblBookStatus
    .Where(s => s.User.Email == UserEmail
        && s.Book != null)
    .Select(s => new DisplayBookDTO
    {
        Status = s.Status,
        BookTitle = s.Book.Title,
        BookAuthor = s.Book.Author
    })
    .ToListAsync();

無需單獨查詢每個表,然后加入。 讓 LINQ 為您做。

var UserEmail = HttpContext.Session.GetString("Email");

var books = _context.TblBookStatus
     .Where(
        tbs => (tbs.Book != null && tbs.BookId == tbs.Book.BookId) &&
               (tbs.User != null && tbs.UserEmail == tbs.User.Email) &&
               tbs.UserEmail == UserEmail)
     .Select(tbs => tbs.Book);

因為您在 EF 模型中定義了導航屬性(使用虛擬屬性),所以將自動為您完成連接。 在上面的例子中,我設置了 tbs.BookId == tbs.Book.BookId。 如果您在實體類型配置中定義了外鍵,則不需要這樣做。 您也可以使用 EF 模型中的屬性來定義這些關系。

例子:

[ForeignKey("BookId")]
public virtual TblBook Book { get; set; }

編輯:分解您需要返回的內容:

var books = _context.TblBookStatus
         .Where(
            tbs => (tbs.Book != null && tbs.BookId == tbs.Book.BookId) &&
                   (tbs.User != null && tbs.UserEmail == tbs.User.Email) &&
                   tbs.UserEmail == UserEmail)
         .Select(tbs => new {
                   Status = tbs.Status,
                   BookName = tbs.Book.Name
                             });

暫無
暫無

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

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