Apache Ignite 'Failed to prepare update plan' 在缓存上执行 SQL 查询时

Apache Ignite 'Failed to prepare update plan' when executing SQL query on cache

我正在研究如何在 Ignite 中配置缓存和 tables,然后使用 .NET SDK 通过 SQL API 插入一个条目。

我创建了两个缓存,每个缓存都有一个 table。第一个是通过 CacheClientConfiguration 和 QueryEntities 创建的,第二个是使用 'CREATE TABLE...' DDL 命令创建的。然后我尝试使用 'INSERT INTO...' 将相同的对象(相同的值)插入到两个 table 中。对于使用 'CREATE Table...' 命令创建的 table 它有效,但是对于使用 QueryEntities 创建的 table 我得到一个 IgniteClientException 说明: 'Failed to prepare update plan'。两个 Insert 命令看起来完全一样(除了 table 名称)。

试图告诉我的异常是什么,为什么插入对第二种方法有效但对第一种方法无效?

请参阅下面的示例代码。

正在创建缓存和 tables:

public class ValueClass
{
  [QuerySqlField(IsIndexed = true)]
  public long Id { get; set; }

  [QuerySqlField]
  public string Content { get; set; }
}

var cache01 = igniteClient.CreateCache<long, ValueClass>(new CacheClientConfiguration
{
  Name = "Cache01",
  QueryEntities = new[]
  {
    new QueryEntity(
      typeof(long),
      typeof(ValueClass))
    {
      TableName = "table01"
    }
  },
  SqlSchema = "PUBLIC",
});

var cache02 = igniteClient.CreateCache<long, ValueClass>("Cache02");
cache02.Query(new SqlFieldsQuery(
  "CREATE TABLE IF NOT EXISTS table02 (" +
    "Id BIGINT PRIMARY KEY, " +
    "Content VARCHAR, " +
    ")" +
   "WITH " +
     "\"cache_name=Cache02, " +
     $"VALUE_TYPE={typeof(ValueClass)}" +
     $"\""
   )
   { Schema = "PUBLIC" });

正在执行插入查询:

// EXCEPTION: Apache.Ignite.Core.Client.IgniteClientException: 'Failed to prepare update plan.'
cache01.Query(
  new SqlFieldsQuery(
    "INSERT INTO " +
      "table01 ( " +
        "Id, " +
        "Content ) " +
      "VALUES ( " +
        "?, " +
        "? )"
  )
  {
    Arguments = new object[]
    {
      3,
      "entry3"
    },
    Schema = "PUBLIC"
  });

// This one works
cache02.Query(
  new SqlFieldsQuery(
    "INSERT INTO " +
      "table02 ( " +
        "Id, " +
        "Content ) " +
      "VALUES ( " +
        "?, " +
        "? )"
  )
  {
    Arguments = new object[]
    {
      3,
      "entry3"
    },
    Schema = "PUBLIC"
  });

异常:

Unhandled exception. Apache.Ignite.Core.Client.IgniteClientException: Failed to prepare update plan.
   at Apache.Ignite.Core.Impl.Client.Cache.CacheClient`2.HandleError[T](ClientStatusCode status, String msg)
   at Apache.Ignite.Core.Impl.Client.ClientSocket.DecodeResponse[T](BinaryHeapStream stream, Func`2 readFunc, Func`3 errorFunc)
   at Apache.Ignite.Core.Impl.Client.ClientSocket.DoOutInOp[T](ClientOp opId, Action`1 writeAction, Func`2 readFunc, Func`3 errorFunc)
   at Apache.Ignite.Core.Impl.Client.ClientFailoverSocket.DoOutInOp[T](ClientOp opId, Action`1 writeAction, Func`2 readFunc, Func`3 errorFunc)
   at Apache.Ignite.Core.Impl.Client.Cache.CacheClient`2.DoOutInOp[T](ClientOp opId, Action`1 writeAction, Func`2 readFunc)
   at Apache.Ignite.Core.Impl.Client.Cache.CacheClient`2.Query(SqlFieldsQuery sqlFieldsQuery)
   at ApacheIgniteConfigurationDemo.Worker.ExecuteAsync(CancellationToken stoppingToken) in C:\ApacheIgniteConfigurationDemo\Worker.cs:line 60
   at Microsoft.Extensions.Hosting.Internal.Host.StartAsync(CancellationToken cancellationToken)
   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token)
   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token)
   at Program.<Main>$(String[] args) in C:\ApacheIgniteConfigurationDemo\Program.cs:line 26
   at Program.<Main>(String[] args) [StatusCode=Fail]

Ignite 运行 在 docker 容器中使用默认配置。

解法:

正如@Alexandr Shapkin 所指出的(参见接受的答案)我必须指定“KeyFieldName”,因为我想使用 POJO class 的“Id”字段作为键。

像这样配置 table 适用于我的情况:

var cache01 = igniteClient.CreateCache<long, ValueClass>(new CacheClientConfiguration
{
  Name = "Cache01",
  QueryEntities = new[]
  {
      new QueryEntity(
        typeof(long),
        typeof(ValueClass))
      {
        TableName = "table01",
        KeyFieldName = nameof(ValueClass.Id)
      }
    },
  SqlSchema = "PUBLIC",
});

另一种解决方案是将“_key”行添加到插入命令中:

cache01.Query(
  new SqlFieldsQuery(
    "INSERT INTO " +
      "table01 ( " +
        "_key, " +
        "Id, " +
        "Content ) " +
      "VALUES ( " +
        "?, " +
        "?, " +
        "? )"
  )
  {
    Arguments = new object[]
    {
        3 ,
        3,
        "entry3"
    },
    Schema = "PUBLIC"
  });

我认为这是因为您没有明确地向第一个查询提供 _KEY,并希望将其保留在您的 POJO 模型中。

使用以下配置显式指定密钥配置并尝试一下。

var cache01 = igniteClient.CreateCache<long, ValueClass>(new CacheConfiguration()
            {
                Name = "Cache01",
                QueryEntities = new[]
                {
                    new QueryEntity(
                        typeof(long),
                        typeof(ValueClass))
                    {
                        TableName = "table01",
                        KeyFieldName = "Id",
                        Fields = new List<QueryField>()
                        {
                                new QueryField("Id", typeof(long)),
                                new QueryField("Content", typeof(string)),
                        }
                    }
                },
                SqlSchema = "PUBLIC",
            });