spring-attic / spring-cloud-gcp

Integration for Google Cloud Platform APIs with Spring
Apache License 2.0
704 stars 694 forks source link

Error when comparing Key #2609

Open beunick opened 3 years ago

beunick commented 3 years ago

Hi, I have issue, I am trying to do NOT EQUAL on key and I separate it in two queries as you can see in the code below. But I keep having error about the " ID property was required but does not exist for the type". Can you please let me know why that ?

` @Repository public interface ProductRepository extends DatastoreRepository<Product, Key> { @Query("select * from product where id > @product_key and code = @product_code") Product existsByCodeLow(@Param("product_code")String code, @Param("product_key")Key key);

  @Query("select * from product  where id < @product_key and code = @product_code")
   Product existsByCodeSup(@Param("product_code")String code, @Param("product_key")Key key);

} `

Here is the error I got:

org.springframework.cloud.gcp.data.datastore.core.mapping.DatastoreDataException: An ID property was required but does not exist for the type: class com.google.cloud.datastore.Key

dmitry-s commented 3 years ago

@beunick in this case you should pass an entity instead of a Key. It will be converted to a key automatically.

Let me know if that works for you.

Thanks

beunick commented 3 years ago

@dmitry-s Thanks for the note but no it is not working. here is my code change.

@Query("select * from product where id < @product and code = @product_code") Product existsByCodeSup(@Param("product_code")String code, @Param("product") Product product);

And I still have this error message: An ID property was required but does not exist for the type: class com.google.cloud.datastore.Key

Any other idea ?

Thanks

dmitry-s commented 3 years ago

@beunick the message looks strange because you don't have any parameters of type com.google.cloud.datastore.Key.

Could you provide sample code so I could try to replicate your issue?

Thanks

beunick commented 3 years ago

Sorry @dmitry-s sorry I copy and paste the wrong error message, that message was what I got before code change :

When changing the code as suggested: @Query("select * from product where id < @product and code = @product_code") Product existsByCodeSup(@Param("product_code")String code, @Param("product") Product product);

Here is the message I still have:

` com.google.datastore.v1.client.DatastoreException: no matching index found. recommended index is:

dmitry-s commented 3 years ago

@beunick ok that makes sense.

Datastore requires you to create indexes for inequality filters unless you only use one field (see https://cloud.google.com/datastore/docs/concepts/queries#inequality_filters_are_limited_to_at_most_one_property).

It's very easy to create indexes, see https://cloud.google.com/datastore/docs/concepts/indexes for reference.

Let me know if that works for you.

Thanks

beunick commented 3 years ago

Thanks @dmitry-s I did add the indexes, I now have no error, the query seems to be executing successfully but the problem is I have no value return. If I do this (Superior): @Query("select * from product where id < @product and code = @product_code") Product existsByCodeSup(@Param("product_code")String code, @Param("product") Product product); It return nothing.

When I do this (Inferior) @Query("select * from product where id > @product and code = @product_code") Product existsByCodeLow(@Param("product_code")String code, @Param("product") Product product); It return nothing

Even when I do this (Equal): @Query("select * from product where id = @product and code = @product_code") Product existsByCodeSup(@Param("product_code")String code, @Param("product") Product product);

I have a feeling that the compare with the id (Key) inside the @Query() is not working at all... Unless I miss something. I really don't know what else to try to do the NOT Equal on the Key. This is strange.

Any help will be much appreciated. Thank You!!

dmitry-s commented 3 years ago

@beunick I tested this approach and it works for me.

I would recommend testing your GQL query in GCP Datastore console in the web ui to make sure the query works as you expect. You can use key literals in GQL using this syntax: Key(kind, id)

So your query would look similar to this one:

select * from product where id > Key(your_kind, 1) and code = 9
beunick commented 3 years ago

Hi @dmitry-s Thanks for the note. Have you tried with UUID ? I notice that you have Long there, but in my case I am using UUID though.

I just tested this query below in GCP datastore console and the return value is empty.

select * from product where id < Key(product, '9ad36754-df55-45f5-811d-2d151c027774') and code = 'string2H'

select * from product where id = Key(product, '9ad36754-df55-45f5-811d-2d151c027774') and code = 'string2H'

select * from product where id > Key(product, '9ad36754-df55-45f5-811d-2d151c027774') and code = 'string2H'

All those query in the console return empty value.

I really don't know why.

beunick commented 3 years ago

Hi @dmitry-s any luck testing this using Key with UUID ?

dmitry-s commented 3 years ago

Hi @beunick,

I just verified that it works with string keys.

SELECT * FROM `books` where __key__ = Key(books, '76dac4ea-2ab2-4319-9b5b-128b8ba86588') and author = 'author2'

I am not sure why your query is not working. Try removing the and code = 'string2H' part to see if the first part of the filter works.

beunick commented 3 years ago

Hi @dmitry-s Thanks for the note. From the console when using key instead of id it works indeed with UUID. All the query I describe in my previous post now work with key in the console.

Inside my application now, when I replace "id" by "key" like this @Query("select * from product where __key__ > @product and code = @product_code ")

I have this error: org.springframework.cloud.gcp.data.datastore.core.mapping.DatastoreDataException: An ID property was required but does not exist for the type: class com.google.cloud.datastore.Key

I am wondering if in your test you can make it work successfully using UUID in the Key inside your @Query in your code ?

dmitry-s commented 3 years ago

@beunick I've tested that today and have confirmed that it works with String ID as well as Long.

The error indicates that there was an issue with retrieving id property from an entity.

Just to clarify, are you using String field annotated with @Id in your pojo?

Could you share the source code for both your entity and the method from the repository?

Thanks

beunick commented 3 years ago

Thank you @dmitry-s for the note. Below you will see code for Entity, Repository, Service and the code I create to generate the Key.

The code in Repository with ID in the query: `.

   @Repository

    public interface ProductRepository extends DatastoreRepository<Product, Key> { 

@Query("select * from product where id < @product and code = @product_code and store_ref_id= @store_id")
Product existsByCodeWithKeySup(@Param("product")Product product, @Param("product_code")String code, 
    @Param("store_id")Key storeRefKey);

    @Query("select * from product where id > @product and code = @product_code and store_ref_id= @store_id")
Product existsByCodeWithKeyLow(@Param("product")Product product, @Param("product_code")String code, 
    @Param("store_id")Key storeRefKey);

    }

`

The code in Repository with key in the query:

`

  @Repository

   public interface ProductRepository extends DatastoreRepository<Product, Key> { 

@Query("select * from product where __key__ < @product and code = @product_code and store_ref_id= @store_id")
Product existsByCodeWithKeySup(@Param("product")Product product, @Param("product_code")String code, 
    @Param("store_id")Key storeRefKey);

    @Query("select * from product where __key__ > @product and code = @product_code and store_ref_id= @store_id")
Product existsByCodeWithKeyLow(@Param("product")Product product, @Param("product_code")String code, 
    @Param("store_id")Key storeRefKey);

`

Product Entity:

`

   @Entity(name="product")
   public class Product {

    @Id
private Key id;

private String name;

private String code;

    @Field(name="store_ref_id")
    private Key storeId

    // GETTER and SETTER

} `

In the service: `

   private void validateUniqueProductUpdate(Product product) {
             Product productFoundSup = this.productRepo.existsByCodeWithKeySup(product, product.getCode(), product.getStoreId());
    Product productFoundLow = this.productRepo.existsByCodeWithKeyLow(product, product.getCode(), product.getStoreId());

    //....REST OF CODE

}

`

By the way just to let you know, here is the method that I used to generate my Key every time I create a new entity before saving to the DB: `

   public Key getIdCreation(String kindName) {
    Datastore datastore = DatastoreOptions.getDefaultInstance().getService();

    Key id = datastore.newKeyFactory()
            .setKind(kindName)
            .newKey(UUID.randomUUID().toString());
    return id;
}

`

dmitry-s commented 3 years ago

Hi @beunick ,

I was unable to replicate the issue using the code you provided - everything worked as expected for me. Could you create a small application that I can run and get this error message? (perhaps on github)

I am curious - could you explain what exactly you are trying to accomplish with the validateUniqueProductUpdate method?

Btw, the queries you use could be expensive because they are going to fetch all rows. I would recommend using limit 1 if you just need one entity.

Also, which version of spring-cloud-gcp are you using?

Thanks

beunick commented 3 years ago

Hi @dmitry-s, sorry for the late reply and thanks for the note Sure I can try to create a small application on Github and share it with you. Before I do that you asked me a very good question about the version I am using, maybe thats why we don't have the same result...

Here is what I have in my POM file: `

org.springframework.cloud spring-cloud-gcp-starter-data-datastore 1.2.5.RELEASE ` It is the latest version ?
meltsufin commented 3 years ago

The latest version is 1.2.6.RELEASE, but it shouldn't materially change anything.

kioie commented 3 years ago

Hi @beunick did you eventually figure this out? Are you still planning to share the sample application?