EF Core 一对多 Linq 查询

问题描述 投票:0回答:1

我在两个实体之间具有一对多关系,并且需要查询这两个实体的组合。

这是一个File模型:

 public class FileMetadata
    {
        [Key]
        public int Id { get; set; }
        public string Name { get; set; }
        public string Category { get; set; } = string.Empty;
        public string Description { get; set; } = string.Empty;
        public string UserName { get; set; }
        public DateTime UploadDate { get; set; }
        public int FileContentId { get; set; }
        public FileContent Content { get; set; }
        public int UserId { get; set; }
        public User User { get; set; }
    }

另一个是Tag模型:

public class FileTag
    {
        [Key]
        public int Id { get; set; }
        public string Text { get; set; }
        public int FileMetadataId { get; set; }
        public FileMetadata Metadata { get; set; }
    }

关系的本质是,一个文件可以有一对多的标签。我需要做的是实现一个搜索方法,它可以搜索文件的内容(描述、名称等),但是,搜索该文件的所有标签。这就是问题所在,我找不到一种高效的方法来做到这一点。

这是我到目前为止所做的,它给了我预期的结果,但是,效率不高:

 public async Task<ServiceResponse<FileSearchResult>> SearchFileMetaData(string searchText, int page, float resultsPerPage)
    {
        var pageCount = Math.Ceiling((await FindFilesBySearchText(searchText)).Count / resultsPerPage);

        //Add tags to descriptions
        var extendedFiles = _context.Files.ToList();
        var tags = _context.FileTags.ToList();

        foreach (var file in extendedFiles)
        {
            var thisFilesTags = tags.Where(t => t.FileMetadataId == file.Id).ToList();
            foreach (var tag in thisFilesTags)
            {
                file.Description += tag.Text;
            }
        }

        //Search files with metadata matching the search text.
        var files = extendedFiles
                        .Where(f => f.Name.ToLower().Contains(searchText.ToLower())
                        || f.Description.ToLower().Contains(searchText.ToLower()))
                        .Skip((page - 1) * (int)resultsPerPage)
                        .Take((int)resultsPerPage)
                        .ToList();

        var response = new ServiceResponse<FileSearchResult>
        {
            Data = new FileSearchResult
            {
                Files = files,
                ThisPageNumber = page,
                TotalPages = (int)Math.Floor(pageCount)
            }
        };
        return response;
    }

我从数据库中获取所有文件和标签,循环使用该文件实体的标签构建描述字段,然后执行 Linq 操作来过滤搜索文本。

怎样才能仍然得到预期的结果,但提高性能,但又不会得到不必要的记录?

此外,是否可以通过连接这两个实体的更好的 Linq 查询来解决这个问题?或者,关系/表是否需要重新定义?

c# performance linq entity-framework-core relational-database
1个回答
0
投票

尝试以下查询。它尝试在实现之前过滤掉文件。当然这不是理想的解决方案,

Contains
执行全表扫描,如果表很大,这可能会影响性能。

public async Task<ServiceResponse<FileSearchResult>> SearchFileMetaData(string searchText, int page, float resultsPerPage)
{
    searchText = searchText.ToLower();

    var filesQuery = _context.Files
        .Where(f => f.Name.ToLower().Contains(searchText)
            || f.Description.ToLower().Contains(searchText)
            || _context.FileTags.Any(t => t.FileMetadataId == f.Id && t.Text.ToLower().Contains(searchText))
        );

    var pageCount = Math.Ceiling((await filesQuery.CountAsync()) / resultsPerPage);

    var filesQuery = filesQuery
        .Skip((page - 1) * (int)resultsPerPage)
        .Take((int)resultsPerPage)
        .AsNoTracking()
        .ToList();

    var response = new ServiceResponse<FileSearchResult>
    {
        Data = new FileSearchResult
        {
            Files = files,
            ThisPageNumber = page,
            TotalPages = (int)Math.Floor(pageCount)
        }
    };

    return response;
}
© www.soinside.com 2019 - 2024. All rights reserved.