我开发了一个简单的应用程序,类似于聊天,其中每条消息都可能包含文本和文件。 实体是这样相关的:
消息组 -> 每个消息组都有一个消息集合 -> 每个消息都有一个属性 'FileCollection' -> 'File collection' 有 4 个集合:图像、视频、音频、文件。它们都在数据库中具有相同的关系。为了在此处显示此逻辑,我的查询是获取所有消息组及其实体:
var messageGroups = await _db.MessageGroups
.Where(mg => mg.UserId == id)
.Include(m => m.Messages).ThenInclude(mes => mes.FileCollection.Images)
.Include(m => m.Messages).ThenInclude(mes => mes.FileCollection.Video)
.Include(m => m.Messages).ThenInclude(mes => mes.FileCollection.Audio)
.Include(m => m.Messages).ThenInclude(mes => mes.FileCollection.Files)
.ToListAsync();
问题是每种类型的文件(图像、音频等)在 Db(EF Core 中的属性)中都有一个“数据”列,其中包含它们的 blob 数据。我想从查询中排除所有 blob,因为从 Db 加载所有用户文件的查询变得非常繁重。像这样的东西(但排除方法不存在):
.Include(m => m.Messages).ThenInclude(mes => mes.FileCollection.Video).exclude(video => video.Data);
有没有办法在查询结束时使用显式加载?或者也许有像 [JsonIgnore] 这样的属性从 Json 序列化中排除了类属性?或者其他方法?
如果有帮助:ImageFile、AudioFile 等继承自 File 超类:
public class File
{
[Column("id")]
public int Id { get; set; }
[Column("content_type")]
public string ContentType { get; set; }
[Column("file_name")]
public string FileName { get; set; }
[Column("length")]
public long Length { get; set; }
[Column("related_file_collection_id")]
public int FileCollectionId { get; set; }
public FileCollection FileCollection { get; set; }
}
public class ImageFile : File
{
[Column("data")]
public byte[] Data { get; set; }
}
我需要来自“File”类的所有属性,而不需要来自其子类的“Data”属性。
答案 0 :(得分:1)
我认为最好的方法是使用 Table Splitting.
为包含 Blob 列的实体配置 DbContext不要让名字迷惑你。此技术不是将 Blob 移动到不同的表。相反,它将允许您在同一行中放置两个“实体”。
在您的情况下,您可以将您的 File
与您的 FileData
分开,这意味着您将为每个实体拥有不同的实体,但两者都将存储在同一个表的同一行中。>
通过使用表拆分,您可以.Include
File
并且它不会包含 FileData
,除非您明确告诉 EF Core 这样做。
如果您不想走那条路,我相信您要么需要编写一些自定义选择或自定义 SQL。
答案 1 :(得分:0)
您可以使用 [NotMapped]
属性,但随后您将无法从其他查询的数据库中检索该列。
您也可以创建 DTO 并仅选择所需的属性,但考虑到您的所有包含内容,这并不优雅。
答案 2 :(得分:0)
正如这里所建议的,表拆分可以是答案,但它有点复杂。我刚刚使用 .Select() 修改了我的查询。不是很优雅,我也有一个循环里面的循环,但它有效:
List<MessageGroup> messageGroups = await _db.MessageGroups.Where(mg => mg.UserId == id).AsNoTracking().AsSplitQuery().Include(m => m.Messages).ThenInclude(mes => mes.FileCollection.Images)
.Include(m => m.Messages).ThenInclude(mes => mes.UrlPreviews).ToListAsync();
foreach (var mg in messageGroups)
{
foreach (var m in mg.Messages)
{
m.FileCollection.Video = await _db.Video.Where(video => video.FileCollectionId == m.FileCollection.Id).Select(v => new VideoFile(v.ContentType, v.FileName, v.Length, v.FileCollectionId, null)).ToListAsync();
m.FileCollection.Audio = await _db.Audio.Where(audio => audio.FileCollectionId == m.FileCollection.Id).Select(a => new AudioFile(a.ContentType, a.FileName, a.Length, a.FileCollectionId, null)).ToListAsync();
m.FileCollection.Files = await _db.Files.Where(file => file.FileCollectionId == m.FileCollection.Id).Select(f => new OtherFile(f.ContentType, f.FileName, f.Length, f.FileCollectionId, null)).ToListAsync();
}
}
文件构造函数中的 null 是 byte[] blob 数据应该在的位置。