Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IllegalStateException: Invalid Primary Key when querying models with nullable nested models #3084

Closed
3 of 13 tasks
RobsonT opened this issue May 20, 2023 · 16 comments
Closed
3 of 13 tasks
Assignees
Labels
Android Issues specific to the Android Platform bug Something is not working; the issue has reproducible steps and has been reproduced datastore Issues related to the DataStore Category

Comments

@RobsonT
Copy link

RobsonT commented May 20, 2023

Description

I'm using the datastore to query a table, filtering by a foreign key. when passing the foreign key, some manage to bring the data, but others generate the error: Invalid Primary Key, It should either be single field or of type composite primary key

Categories

  • Analytics
  • API (REST)
  • API (GraphQL)
  • Auth
  • Authenticator
  • DataStore
  • Storage

Steps to Reproduce

The error occurs in some tables with a 1:n relationship, when making the query filtering by the foreign key.

Error:
E/amplify:flutter:datastore(24262): at java.lang.Thread.run(Thread.java:923) E/amplify:flutter:datastore(24262): Caused by: java.lang.IllegalStateException: Invalid Primary Key, It should either be single field or of type composite primary key Primary Key.java.lang.NullPointerException E/amplify:flutter:datastore(24262): at com.amplifyframework.core.model.ModelIdentifier$Helper.getUniqueKey(ModelIdentifier.java:128) E/amplify:flutter:datastore(24262): at com.amplifyframework.core.model.SerializedModel$Builder.serializedData(SerializedModel.java:340) E/amplify:flutter:datastore(24262): at com.amplifyframework.datastore.storage.sqlite.SQLiteStorageAdapter.createSerializedModel(SQLiteStorageAdapter.java:900) E/amplify:flutter:datastore(24262): at com.amplifyframework.datastore.storage.sqlite.SQLiteStorageAdapter.createSerializedModel(SQLiteStorageAdapter.java:872) E/amplify:flutter:datastore(24262): at com.amplifyframework.datastore.storage.sqlite.SQLiteStorageAdapter.lambda$query$5$com-amplifyframework-datastore-storage-sqlite-SQLiteStorageAdapter(SQLiteStorageAdapter.java:444) E/amplify:flutter:datastore(24262): ... 6 more E/amplify:flutter:datastore(24262): Query operation failed. E/amplify:flutter:datastore(24262): DataStoreException{message=Error in querying the model., cause=java.lang.IllegalStateException: Invalid Primary Key, It should either be single field or of type composite primary key Primary Key.java.lang.NullPointerException, recoverySuggestion=See attached exception for details.} E/amplify:flutter:datastore(24262): at com.amplifyframework.datastore.storage.sqlite.SQLiteStorageAdapter.lambda$query$5$com-amplifyframework-datastore-storage-sqlite-SQLiteStorageAdapter(SQLiteStorageAdapter.java:450) E/amplify:flutter:datastore(24262): at com.amplifyframework.datastore.storage.sqlite.SQLiteStorageAdapter$$ExternalSyntheticLambda8.run(Unknown Source:10) E/amplify:flutter:datastore(24262): at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:462) E/amplify:flutter:datastore(24262): at java.util.concurrent.FutureTask.run(FutureTask.java:266) E/amplify:flutter:datastore(24262): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) E/amplify:flutter:datastore(24262): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) E/amplify:flutter:datastore(24262): at java.lang.Thread.run(Thread.java:923) E/amplify:flutter:datastore(24262): Caused by: java.lang.IllegalStateException: Invalid Primary Key, It should either be single field or of type composite primary key Primary Key.java.lang.NullPointerException E/amplify:flutter:datastore(24262): at com.amplifyframework.core.model.ModelIdentifier$Helper.getUniqueKey(ModelIdentifier.java:128) E/amplify:flutter:datastore(24262): at com.amplifyframework.core.model.SerializedModel$Builder.serializedData(SerializedModel.java:340) E/amplify:flutter:datastore(24262): at com.amplifyframework.datastore.storage.sqlite.SQLiteStorageAdapter.createSerializedModel(SQLiteStorageAdapter.java:900) E/amplify:flutter:datastore(24262): at com.amplifyframework.datastore.storage.sqlite.SQLiteStorageAdapter.createSerializedModel(SQLiteStorageAdapter.java:872) E/amplify:flutter:datastore(24262): at com.amplifyframework.datastore.storage.sqlite.SQLiteStorageAdapter.lambda$query$5$com-amplifyframework-datastore-storage-sqlite-SQLiteStorageAdapter(SQLiteStorageAdapter.java:444) E/amplify:flutter:datastore(24262): ... 6 more E/amplify:flutter:datastore(24262): Query operation failed. E/amplify:flutter:datastore(24262): DataStoreException{message=Error in querying the model., cause=java.lang.IllegalStateException: Invalid Primary Key, It should either be single field or of type composite primary key Primary Key.java.lang.NullPointerException, recoverySuggestion=See attached exception for details.} E/amplify:flutter:datastore(24262): at com.amplifyframework.datastore.storage.sqlite.SQLiteStorageAdapter.lambda$query$5$com-amplifyframework-datastore-storage-sqlite-SQLiteStorageAdapter(SQLiteStorageAdapter.java:450) E/amplify:flutter:datastore(24262): at com.amplifyframework.datastore.storage.sqlite.SQLiteStorageAdapter$$ExternalSyntheticLambda8.run(Unknown Source:10) E/amplify:flutter:datastore(24262): at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:462) E/amplify:flutter:datastore(24262): at java.util.concurrent.FutureTask.run(FutureTask.java:266) E/amplify:flutter:datastore(24262): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) E/amplify:flutter:datastore(24262): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) E/amplify:flutter:datastore(24262): at java.lang.Thread.run(Thread.java:923) E/amplify:flutter:datastore(24262): Caused by: java.lang.IllegalStateException: Invalid Primary Key, It should either be single field or of type composite primary key Primary Key.java.lang.NullPointerException E/amplify:flutter:datastore(24262): at com.amplifyframework.core.model.ModelIdentifier$Helper.getUniqueKey(ModelIdentifier.java:128) E/amplify:flutter:datastore(24262): at com.amplifyframework.core.model.SerializedModel$Builder.serializedData(SerializedModel.java:340) E/amplify:flutter:datastore(24262): at com.amplifyframework.datastore.storage.sqlite.SQLiteStorageAdapter.createSerializedModel(SQLiteStorageAdapter.java:900) E/amplify:flutter:datastore(24262): at com.amplifyframework.datastore.storage.sqlite.SQLiteStorageAdapter.createSerializedModel(SQLiteStorageAdapter.java:872) E/amplify:flutter:datastore(24262): at com.amplifyframework.datastore.storage.sqlite.SQLiteStorageAdapter.lambda$query$5$com-amplifyframework-datastore-storage-sqlite-SQLiteStorageAdapter(SQLiteStorageAdapter.java:444) E/amplify:flutter:datastore(24262): ... 6 more

Screenshots

No response

Platforms

  • iOS
  • Android
  • Web
  • macOS
  • Windows
  • Linux

Flutter Version

3.3.10

Amplify Flutter Version

0.6.13

Deployment Method

Amplify CLI

Schema

No response

@Jordan-Nelson Jordan-Nelson added pending-triage This issue is in the backlog of issues to triage datastore Issues related to the DataStore Category labels May 22, 2023
@Jordan-Nelson
Copy link
Contributor

@RobsonT - Could you share your schema (at least the portion that includes the model you are query, and any models it is related to) and the code that you are running that causes this exception? Thanks.

@Jordan-Nelson Jordan-Nelson added the pending-response Issue is pending response from the issue requestor label May 22, 2023
@RobsonT
Copy link
Author

RobsonT commented May 22, 2023

Hello @Jordan-Nelson ,

Schema:

type Safra @model @auth(rules: [{allow: public}]) {
  id: ID!
  data_plantio: AWSDate
  finalizada: Boolean
  dataFinalizacao: AWSDate
  talhaoID: ID! @index(name: "byTalhao")
  subdivisaoID: ID @index(name: "bySubdivisao")
  propriedadecultivoID: ID! @index(name: "byPropriedadeCultivo")
  Manejos: [Manejo] @hasMany(indexName: "bySafra", fields: ["id"])
  LoteSafras: [LoteSafra] @hasMany(indexName: "bySafra", fields: ["id"])
  Perdas: [Perda] @hasMany(indexName: "bySafra", fields: ["id"])
  OcorrenciaSafras: [OcorrenciaSafra] @hasMany(indexName: "bySafra", fields: ["id"])
  responsavel_atualizacao_id: String
  responsavel_cadastro_id: String
  talhao: Talhao @belongsTo(fields: ["talhaoID"])
  subdivisao: Subdivisao @belongsTo(fields: ["subdivisaoID"])
  propriedadeCultivo: PropriedadeCultivo @belongsTo(fields: ["propriedadecultivoID"])
}

type Manejo @model @auth(rules: [{allow: public}]) {
  id: ID!
  observacao: String
  dataAplicacao: AWSDate
  horario: AWSTime
  duracaoMinutos: Int
  quantidadeVolumeCalda: Float
  dataSolicitacao: AWSDate
  pendente: Boolean
  safraID: ID! @index(name: "bySafra")
  propriedadeservicoID: ID @index(name: "byPropriedadeServico")
  valorServico: Float
  Solicitante: String
  responsavel: String
  ManejoProdutos: [ManejoProduto] @hasMany(indexName: "byManejo", fields: ["id"])
  equipamentoaplicacaoID: ID @index(name: "byEquipamentoAplicacao")
  modoaplicacaoID: ID @index(name: "byModoAplicacao")
  responsavel_cadastro_id: String
  responsavel_atualizacao_id: String
  safra: Safra @belongsTo(fields: ["safraID"])
  propriedadeServico: PropriedadeServico @belongsTo(fields: ["propriedadeservicoID"])
  modoAplicacao: ModoAplicacao @belongsTo(fields: ["modoaplicacaoID"])
  equipamentoAplicacao: EquipamentoAplicacao @belongsTo(fields: ["equipamentoaplicacaoID"])
}

Code:

for (var talhao in talhoes) {
      final safra = await Amplify.DataStore.query(Safra.classType, where: Safra.TALHAO.eq(talhao.id)); // Error in this line
      safras = [...safras, ...safra.map((e) => e.id).toList()];
    }

@Jordan-Nelson Jordan-Nelson removed the pending-response Issue is pending response from the issue requestor label May 22, 2023
@RobsonT
Copy link
Author

RobsonT commented May 23, 2023

I did some tests and managed to run the project. Apparently the error occurs when "subdivisaoID" in "Safra" is null, working correctly when this field is filled. However, this field is marked as "not required" precisely because it does not need a subdivisaoID in some cases.

@Jordan-Nelson
Copy link
Contributor

Thanks. Can you share the definitions for Talhao and Subdivisao as well?

@Jordan-Nelson Jordan-Nelson added the pending-response Issue is pending response from the issue requestor label May 24, 2023
@cwomack cwomack added Investigating Issues that are assigned and are being looked into and removed pending-triage This issue is in the backlog of issues to triage labels May 25, 2023
@RobsonT
Copy link
Author

RobsonT commented May 29, 2023

@Jordan-Nelson, These are the models:

type Talhao @model @auth(rules: [{allow: public}]) {
id: ID!
nome: String
propriedadeID: ID! @Index(name: "byPropriedade")
Subdivisaos: [Subdivisao] @hasmany(indexName: "byTalhao", fields: ["id"])
Safras: [Safra] @hasmany(indexName: "byTalhao", fields: ["id"])
Coordenadas: [Coordenada] @hasmany(indexName: "byTalhao", fields: ["id"])
OutrasAreasPropriedades: [OutrasAreasPropriedade] @hasmany(indexName: "byTalhao", fields: ["id"])
responsavel_cadastro_id: String
responsavel_atualizacao_id: String
ativo: Boolean
propriedade: Propriedade @belongsTo(fields: ["propriedadeID"])
area_hectares: Float
}

type Subdivisao @model @auth(rules: [{allow: public}]) {
id: ID!
complemento: String
cateroriasubdivisaoID: ID! @Index(name: "byCategoriaSubdivisao")
talhaoID: ID! @Index(name: "byTalhao")
propriedadeID: ID! @Index(name: "byPropriedade")
Safras: [Safra] @hasmany(indexName: "bySubdivisao", fields: ["id"])
Coordenadas: [Coordenada] @hasmany(indexName: "bySubdivisao", fields: ["id"])
responsavel_atualizacao_id: String
responsavel_cadastro_id: String
subdivisao_pai: String
ativo: Boolean
propriedade: Propriedade @belongsTo(fields: ["propriedadeID"])
talhao: Talhao @belongsTo(fields: ["talhaoID"])
categoriaSubdivisao: CategoriaSubdivisao @belongsTo(fields: ["cateroriasubdivisaoID"])
area_hectares: Float
}

@Jordan-Nelson Jordan-Nelson removed the pending-response Issue is pending response from the issue requestor label May 30, 2023
@Jordan-Nelson
Copy link
Contributor

@RobsonT - Apologies for the delay in a response.

I see you indicated that you are using iOS and Android in the issue. The logs provided are from Android. Can you confirm you are experiencing this issue on iOS? Note: you may need to run the app from xcode to see the native iOS logs.

@Jordan-Nelson Jordan-Nelson added the pending-response Issue is pending response from the issue requestor label Jun 14, 2023
@Jordan-Nelson
Copy link
Contributor

Hi @RobsonT - Please let me know if you are still experiencing this issue.

@Jordan-Nelson Jordan-Nelson added pending-close-response-required The issue will be closed if details necessary to reproduce the issue are not provided within 7 days. and removed pending-response Issue is pending response from the issue requestor labels Jun 20, 2023
@RobsonT
Copy link
Author

RobsonT commented Jun 20, 2023

@Jordan-Nelson, Sorry for the delay.

The error occurs in both android and iOS.

@ragingsquirrel3 ragingsquirrel3 removed the pending-close-response-required The issue will be closed if details necessary to reproduce the issue are not provided within 7 days. label Jun 20, 2023
@Jordan-Nelson
Copy link
Contributor

Hi @RobsonT - I was able to create a minimal reproduction of this issue. However, I am only seeing the issue on Android. The exception is not thrown on iOS. Can you confirm you are also seeing this on iOS?

Here is the schema, app, and steps I took to reproduce:

Repro steps:

  1. Add Plot (Talhao)
  2. Run query, observe no issues
  3. Add Crop (Safra) with Talhao and Subdivisao
  4. Run query, observe no issues
  5. Add Crop (Safra) with Talhao but without Subdivisao
  6. Run query, observe the exception Invalid Primary Key, It should either be single field or of type composite primary key Primary Key
input AMPLIFY {
  globalAuthRule: AuthRule = { allow: public }
} # FOR TESTING ONLY!

# Crop
type Safra @model {
  id: ID!
  talhaoID: ID! @index(name: "byTalhao")
  subdivisaoID: ID @index(name: "bySubdivisao")
  talhao: Talhao @belongsTo(fields: ["talhaoID"])
  subdivisao: Subdivisao @belongsTo(fields: ["subdivisaoID"])
}

# Plot
type Talhao @model {
  id: ID!
  nome: String
  Subdivisaos: [Subdivisao] @hasMany(indexName: "byTalhao", fields: ["id"])
  Safras: [Safra] @hasMany(indexName: "byTalhao", fields: ["id"])
}

# Subdivision
type Subdivisao @model {
  id: ID!
  talhaoID: ID! @index(name: "byTalhao")
  Safras: [Safra] @hasMany(indexName: "bySubdivisao", fields: ["id"])
  talhao: Talhao @belongsTo(fields: ["talhaoID"])
}

App

import 'package:flutter/material.dart';

import 'package:amplify_flutter/amplify_flutter.dart';
import 'package:amplify_datastore/amplify_datastore.dart';

import 'amplifyconfiguration.dart';
import 'models/ModelProvider.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  void initState() {
    super.initState();
    _configureAmplify();
  }

  Future<void> _configureAmplify() async {
    final datastorePlugin = AmplifyDataStore(
      modelProvider: ModelProvider.instance,
    );
    await Amplify.addPlugin(datastorePlugin);
    try {
      await Amplify.configure(amplifyconfig);
    } on AmplifyAlreadyConfiguredException {
      safePrint('Amplify already configured.');
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('My App'),
          actions: [
            FilledButton(
              onPressed: Amplify.DataStore.clear,
              child: const Text('Clear DB'),
            ),
          ],
        ),
        body: const Center(
          child: Column(
            children: [
              FilledButton(
                onPressed: addPlot,
                child: Text('Add Plot'),
              ),
              FilledButton(
                onPressed: addCrop,
                child: Text('Add Crop'),
              ),
              FilledButton(
                onPressed: addCropWithoutSubdivision,
                child: Text('Add Crop without Subdivision'),
              ),
              FilledButton(
                onPressed: queryCrops,
                child: Text('Query Crops'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

Future<void> addPlot() async {
  final talhao = Talhao(nome: 'New Talhao ${uuid()}');
  try {
    await Amplify.DataStore.save(talhao);
    safePrint('New plot saved!');
  } on DataStoreException catch (e) {
    safePrint('Something went wrong saving model: ${e.message}');
  }
}

Future<void> addCrop() async {
  final talhao = Talhao(nome: 'New Talhao ${uuid()}');
  final subdivisao = Subdivisao(talhao: talhao);
  final safra = Safra(talhao: talhao, subdivisao: subdivisao);
  try {
    await Amplify.DataStore.save(talhao);
    await Amplify.DataStore.save(subdivisao);
    await Amplify.DataStore.save(safra);

    safePrint('New crop saved!');
  } on DataStoreException catch (e) {
    safePrint('Something went wrong saving model: ${e.message}');
  }
}

Future<void> addCropWithoutSubdivision() async {
  final talhao = Talhao(nome: 'New Talhao ${uuid()}');
  final safra = Safra(talhao: talhao);
  try {
    await Amplify.DataStore.save(talhao);
    await Amplify.DataStore.save(safra);
    safePrint('New crop saved!');
  } on DataStoreException catch (e) {
    safePrint('Something went wrong saving model: ${e.message}');
  }
}

Future<void> queryCrops() async {
  final talhoes = await Amplify.DataStore.query(Talhao.classType);
  for (var talhao in talhoes) {
    safePrint('talhao: ${talhao.id}');
    final safras = await Amplify.DataStore.query(
      Safra.classType,
      where: Safra.TALHAO.eq(talhao.id),
    );
    for (final safra in safras) {
      safePrint('safra: ${safra.id}');
    }
  }
}

@Jordan-Nelson Jordan-Nelson added bug Something is not working; the issue has reproducible steps and has been reproduced and removed Investigating Issues that are assigned and are being looked into labels Jun 23, 2023
@Jordan-Nelson Jordan-Nelson added the Android Issues specific to the Android Platform label Jun 23, 2023
@RobsonT
Copy link
Author

RobsonT commented Jun 28, 2023

@Jordan-Nelson

We ran some tests and the error did not actually occur on iOS. We probably confused some mistake we made with this inavlid primary key error. So at the moment it only happens on android.

@RobsonT
Copy link
Author

RobsonT commented Jul 4, 2023

@Jordan-Nelson

I don't know if it's related, but we have an error in another table that only occurs on iOS, apparently also referring to null optional fields.

amplify_datastore/FlutterSerializedModel.swift:233: Fatal error: Unexpectedly found nil while unwrapping an Optional value

@RobsonT
Copy link
Author

RobsonT commented Jul 16, 2023

@Jordan-Nelson

Any updates on this issue?

@Jordan-Nelson
Copy link
Contributor

@RobsonT - This seems to be an issue that will need to be addressed in Amplify Android. I opened an issue (linked above) in Amplify Android to track this. I don't have a timeline for a fix at the moment.

I don't think the other error you have shared is related. If you have reproducible steps for that, can you open a new issue?

@Jordan-Nelson Jordan-Nelson changed the title Unable to get some data when doing a query IllegalStateException: Invalid Primary Key when querying models with nullable nested models Aug 2, 2023
@NikaHsn NikaHsn added the requires-android-fix This issue is the result of an underlying Amplify Android issue that needs to be fixed. label Aug 10, 2023
@Jordan-Nelson
Copy link
Contributor

FYI - Amplify Android issue - aws-amplify/amplify-android#2488

@khatruong2009
Copy link
Contributor

Hi @RobsonT, the amplify-android team has a PR open with a fix for this issue. After it is released on their library, the bug fix will subsequently be released on amplify-flutter. Thank you for your patience.

@khatruong2009 khatruong2009 added pending-release Issues that have been addressed in main but have not been released and removed requires-android-fix This issue is the result of an underlying Amplify Android issue that needs to be fixed. pending-release Issues that have been addressed in main but have not been released labels Feb 1, 2024
@NikaHsn
Copy link
Contributor

NikaHsn commented Apr 17, 2024

Thank you for your patience. The issue has been fixed in version 1.8.0. and I'm closing it. However, if you encounter any issues after updating to version 1.8.0, please don't hesitate to reopen it.

@NikaHsn NikaHsn closed this as completed Apr 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Android Issues specific to the Android Platform bug Something is not working; the issue has reproducible steps and has been reproduced datastore Issues related to the DataStore Category
Projects
None yet
Development

No branches or pull requests

6 participants