问题描述
我使用json序列化将字段列表存储在字段中
型号:
public class Video
{
public int Id { get; set; }
public string Name { get; set; }
public virtual IList<int> AllRelatedIds { get; set; }
}
上下文:
modelBuilder.Entity<Video>(entity =>
{
entity.Property(p => p.AllRelatedIds).HasConversion(
v => JsonConvert.SerializeObject(v,new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }),v => JsonConvert.DeserializeObject<IList<int>>(v,new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore })
);
});
它工作正常,添加,编辑,删除项目很容易,并且在sql数据库中像json一样存储为 [11000,12000,13000]
一切都很好,但是!想要在此列表上查询时,我会得到奇怪的答复。
位置:
_context.Set<Video>().Where(t=>t.AllRelatedIds.contains(11000))
返回空,但是,如果我要求返回所有 AllRelatedIds 项,则某些记录的exp值为11000。
计数:
_context.Set<Video>().Count(t=>t.AllRelatedIds.contains(11000))
返回无法翻译。以可转换的形式重写查询,或者通过插入对AsEnumerable(),AsAsyncEnumerable(),ToList()或ToListAsync()的调用来显式切换到客户端评估。
EF Core有什么问题?我什至测试了t=>t.AllRelatedIds.ToList().contains(11000)
,但没有改变
我该怎么办?我不想有更多的表,我已经使用了数百次这种方法,但似乎从未对其查询。
解决方法
Json序列化/反序列化发生在应用程序级别。 EF Core将IList<int>
对象序列化为值[11000,12000,13000]
,然后将其发送到数据库进行存储,并将值[11000,13000]
反序列化为IList<int>
对象在之后从数据库中检索它。数据库内部什么也没有发生。您的数据库无法在[11000,13000]
上作为数字的集合进行操作。对于数据库,它是一条数据。
如果您尝试以下查询-
var videos = _context.Set<Video>().ToList();
var video = _context.Set<Video>().FirstOrDefault(p=> p.Id == 2);
您将获得预期的结果,EF Core可以完美地完成工作。
问题是,当您查询类似-
_context.Set<Video>().Where(t=> t.AllRelatedIds.Contains(11000))
EF Core将无法将t.AllRelatedIds.Contains(11000)
部分转换为SQL。 EF Core只能对其进行序列化/反序列化,因为您已告知它(以及如何)。但是如上所述,您的数据库无法作为整数的集合在[11000,13000]
上进行操作。因此,EF Core无法将t.AllRelatedIds.Contains(11000)
转换为对数据库有意义的任何内容。
一种解决方案是获取所有视频的列表,以便EF Core可以将AllRelatedIds
反序列化为IList<int>
,然后可以在其上应用LINQ-
var allVideos = _context.Set<Video>().ToList();
var selectedVideos = allVideos.Where(t=> t.AllRelatedIds.Contains(11000)).ToList();
但是,从性能角度来看,不是每次都不必要/过大或效率低下时获取所有视频吗?当然是。但是正如评论所暗示的那样,您的数据库设计/使用方法存在一些缺陷。