繁体   English   中英

如何在 Npgsql.EntityFrameworkCore 中查询具有 JSON 数组的列

[英]How to query against a column that has a JSON Array in Npgsql.EntityFrameworkCore

笔记:

  • 使用 Npsql.EntityFrameworkCore.PostgreSQL v3.1.4
  • 使用 Npgsql v4.1.3.1
  • 使用代码优先方法

我有下表(称为汽车): 在此处输入图片说明

它有两列:

  • LicenseNumber(输入文本)(在 Car.cs 模型中输入字符串)
  • KitchenIntegrations (type jsonb) (type List in Car.cs) 其中 Integrations 是一个集成类型的列表。

Car 类看起来像这样:

public class Car
{
   public string LicenseNumber {get;set;}

   public List<Kitchen> KitchenIntegrations {get;set;}
}

Kitchen.cs 看起来像这样:

public class Kitchen
{
   public int Id {get;set;}

   public string KitchenName {get;set;}
}

最后我的 CarContext.cs 看起来像这样:

public class CarContext : DbContext
{
   public DbSet<Car> Cars { get; set; }

   public CarContext()
   {
   }

   public CarContext(DbContextOptions<CarContext> options) : base(options)
   {
   }

   protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
   {
      optionsBuilder.UseNpgsql("ConnectionStringGoesHere");
   }

   protected override void OnModelCreating(ModelBuilder modelBuilder)
   {
      modelBuilder.HasDefaultSchema("public");
      
      modelBuilder.Entity<Car>(
                builder =>
                {
                    builder.HasKey(i => i.LicenseNumber);
                    builder.Property(i => i.KitchenIntegrations).HasColumnType("jsonb").IsRequired(false);
                }
            );
        }
    }

Cars表中,我只需要获取 Id = 1 的 KitchenIntegration。

我可以在 PSQL 中轻松完成此操作,但是在尝试查询 JSON 数组时遇到问题。

我试过:

var integrations = context.Cars.Select(i => i.KitchenIntegrations.First(o => o.Id == 1)).ToList();

但是遇到无法转换为 SQL/PSQL 的问题。

所以我的问题是如何遍历 EntityFrameworkCore 中的 JSON 数组或列表? (如果可能的话,只将它作为服务器端而不是客户端来做)。

谢谢! 任何帮助是极大的赞赏!

我的 2 美分。 假设您有一个具有以下结构的桌子fixtures (Id, JsonProperty) 假设您在数据库中有一条像这样的记录。

1, [{"Name": "Test", "Value": "123"}, {"Name": "Test2", "Value": "pesho"}]
2, [{"Name": "Test", "Value": "321"}, {"Name": "Test2", "Value": "pesho"}]
3, [{"Name": "Test", "Value": "1123"}, {"Name": "Test2", "Value": "pesho"}]

然后使用EF Core 3.1Npgsql.EntityFrameworkCore.PostgreSQ 3.14你可以这样做:

    var search = "[{\"Value\": \"123\"}]";
    var result = dbContext.Fixtures
                    .FirstOrDefault(s => EF.Functions.JsonContains(s.JsonProperty, search));
    var search2 = "[{\"Name\": \"Test\"}]";
    var multipleResults = dbContext.Fixtures
                    .Where(s => EF.Functions.JsonContains(s.JsonProperty, search2));

我认为这是因为 Entity Framework Core 中的延迟加载

这可以通过var integrations = context.Cars.Select(c => c.KitchenIntegrations).Select(l => l.First(o => o.Id == 1)).ToList(); . 它会抛出:

从“VisitLambda”调用时,重写“System.Linq.Expressions.ParameterExpression”类型的节点必须返回相同类型的非空值。 或者,覆盖“VisitLambda”并将其更改为不访问此类子项。

但是,我尝试使用var integrations = context.Cars.Include(c => c.KitchenIntegrations).ToList(); Eager Loading (和ThenInclude ),但它抛出错误:

Include 中使用的 Lambda 表达式无效。

我必须将所有Cars预加载到内存中才能使其工作

var integrations = context.Cars
                       .ToList() // Eager load to memory
                       .Select(i => i.KitchenIntegrations.First(o => o.Id == 1))
                       .ToList();

我觉得应该有一种更好(或更正确)的方式来进行急切加载。

(当前)不支持将其转换为 SQL - 对数据库 JSON 列的操作是有限的,请参阅文档以获取支持的翻译列表。

在这种特殊情况下,不清楚如何(有效)将其转换为 SQL。 有关类似问题,请参阅https://github.com/npgsql/efcore.pg/issues/1534

您确实可以按照@han-zhao 的建议在客户端执行投影。 但是,使用 AsEnumerable 来触发客户端评估而不是 ToList:

var integrations = context.Cars
    .AsEnumerable()
    .Select(i => i.KitchenIntegrations.First(o => o.Id == 1))
    .ToList();

这确实具有下载大量不需要的厨房实例的缺点,只是在客户端将它们过滤掉。 如果在性能上有问题,请考虑使用原始 SQL (尽管同样,您想要做的并不是微不足道的)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM