Sql server EF Core 3.1无法查询Json序列化对象
我使用json序列化将列表存储在字段中的ID上 型号:Sql server EF Core 3.1无法查询Json序列化对象,sql-server,entity-framework,asp.net-core,entity-framework-core,jsonserializer,Sql Server,Entity Framework,Asp.net Core,Entity Framework Core,Jsonserializer,我使用json序列化将列表存储在字段中的ID上 型号: public class Video { public int Id { get; set; } public string Name { get; set; } public virtual IList<int> AllRelatedIds { get; set; } } 公开课视频 { 公共int Id{get;set;} 公共字符串名称{get;set;} 公共虚拟IList AllRelate
public class Video
{
public int Id { get; set; }
public string Name { get; set; }
public virtual IList<int> AllRelatedIds { get; set; }
}
公开课视频
{
公共int Id{get;set;}
公共字符串名称{get;set;}
公共虚拟IList AllRelatedId{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 })
);
});
modelBuilder.Entity(Entity=>
{
Property(p=>p.AllRelatedId).HasConversion(
v=>JsonConvert.SerializeObject(v,新的JsonSerializerSettings{NullValueHandling=NullValueHandling.Ignore}),
v=>JsonConvert.DeserializeObject(v,新的JsonSerializerSettings{NullValueHandling=NullValueHandling.Ignore})
);
});
它工作得很好,添加、编辑和删除项目都很容易,并且在SQL数据库中它以类似json的形式存储[11000120001300]
一切都很好,但是!!我一想查询这个列表,就会收到奇怪的回复
其中:
\u context.Set().Where(t=>t.AllRelatedIds.contains(11000))
返回null但是如果我要求返回所有AllRelatedIds项,一些记录的exp值为11000
计数:
\u context.Set().Count(t=>t.AllRelatedIds.contains(11000))
返回无法翻译。以可翻译的形式重写查询,或者通过插入对AsEnumerable()、AsAsAsAsyncEnumerable()、ToList()或ToListSync()的调用显式切换到客户端计算。
EF Core怎么了?我甚至测试了t=>t.AllRelatedIds.ToList().contains(11000)
,但没有任何区别
我该怎么办?我不想有更多的表,我使用了这种方法数百次,但似乎从未对它们进行过查询。Json序列化/反序列化发生在应用程序级别。EF Core将
IList
对象序列化为值[11000120001300]
,然后将其发送到数据库进行存储,并在从数据库检索值[11000120001300]
后将其反序列化为IList
对象。数据库内部没有发生任何事情。您的数据库不能在[11000120001300]
上作为数字集合运行。对于数据库来说,它只是一个数据块
如果您尝试以下查询-
var videos=_context.Set().ToList();
var video=_context.Set().FirstOrDefault(p=>p.Id==2);
您将得到预期的结果,EF Core正在完美地完成它的工作
问题是,当您查询以下内容时-
\u context.Set()。其中(t=>t.allrelatedId.Contains(11000))
EF Core将无法将t.allrelatedId.Contains(11000)
部分转换为SQL。EF Core只能对其进行序列化/反序列化,因为您告诉了它(以及如何进行)。但正如我上面所说,您的数据库不能作为整数集合在[11000120001300]
上运行。因此EF Core无法将t.allrelatedId.Contains(11000)
转换为对数据库有意义的任何内容
解决方案是获取所有视频的列表,以便EF Core可以将allrelatedId
反序列化为IList
,然后您可以对其应用LINQ-
var allVideos=\u context.Set().ToList();
var selectedVideos=allVideos.Where(t=>t.AllRelatedIds.Contains(11000)).ToList();
但是,从性能角度看,每次获取所有视频不是不必要/过度或效率低下吗?当然可以。但正如评论所暗示的,您的数据库设计/使用方法存在一些缺陷。我不得不问,这个数据库有什么问题?您是否尝试将ID存储在JSON字段而不是多对多表中?这是一个明显的数据库设计缺陷。EF是一个ORM,它将对象映射到关系结构,它不能做数据库中不可能的事情。使用多对多表是简单、干净和易于管理的。将所有内容都塞进一个字段都不是,因为它违反了最基本的设计规则——一个字段,一个值。现在不可能使用SQL连接、过滤或查询该字段,如果您使用SQL Server 2016及更高版本,您可以使用JSON函数(JSON_query,JSON_VALUE)来使用该字段,并且您仍然会得到非常糟糕的性能,因为这些值无法被索引。如果您有一个像Oracle这样支持阵列的数据库,您可以使用
VARRAY
,但性能仍然会受到影响我不想有更多的表,
为什么只要您想查询此列表
您没有列表,您就有一个长的不透明字符串,某些函数可以解析它。如果数据库设计正确,甚至可以使用查找多个级别的相关视频。通过使用那个长字符串,您甚至不能在中查询单个值SQL@PanagiotisKanavos我不想在不重要的项目上使用太多的关系,也不想进行sql查询,只想让它们像逗号一样分开enough@PanagiotisKanavos你是对的,我必须把它们存储在数据库中