How to use the exists keyword in Spring Data to check for the existence of an entity? - spring-data

How do I use the 'exists' keyword in Spring Data in a query method?
I would like to have a method like this:
public interface ProfileRepository extends JpaRepository<Profile, Long> {
boolean existsByAttribute(String attribute);
}
where Attribute is a field of the Profile.
A workaround would be to use a custom-implementation. But the appendix defines exists as keyword. Could someone give me an example how to use this keyword?

Documented keywords are intended to be used in combination with a property reference. Thus, the semantics of EXISTS in this case are that it checks whether the property exists. Note, that the part of the documentation is pulled it from Spring Data Commons and the keyword being listed there doesn't mean it's supported in Spring Data JPA (indicated in the first paragraph of the section you linked). Exists is not supported by Spring Data JPA as it only makes sense in MongoDB for example as there's a difference between a field not present entirely and the field available with a logically null value.
So what you're looking for seems to be around the (Is)Null keyword with the current limitation that it would return objects and you'd have to check the returned list for content. There's a ticket to add support for projections for derived query methods which you might wanna follow for further progress.

Related

What are the disadvantages of using records instead of classes?

C# 9 introduces record reference types. A record provides some synthesized methods like copy constructor, clone operation, hash codes calculation and comparison/equality operations. It seems to me convenient to use records instead of classes in general. Are there reasons no to do so?
It seems to me that currently Visual Studio as an editor does not support records as well as classes but this will probably change in the future.
Firstly, be aware that if it's possible for a class to contain circular references (which is true for most mutable classes) then many of the auto generated record members can StackOverflow. So that's a pretty good reason to not use records for everything.
So when should you use a record?
Use a record when an instance of a class is entirely defined by the public data it contains, and has no unique identity of it's own.
This means that the record is basically just an immutable bag of data. I don't really care about that particular instance of the record at all, other than that it provides a convenient way of grouping related bits of data together.
Why?
Consider the members a record generates:
Value Equality
Two instances of a record are considered equal if they have the same data (by default: if all fields are the same).
This is appropriate for classes with no behavior, which are just used as immutable bags of data. However this is rarely the case for classes which are mutable, or have behavior.
For example if a class is mutable, then two instances which happen to contain the same data shouldn't be considered equal, as that would imply that updating one would update the other, which is obviously false. Instead you should use reference equality for such objects.
Meanwhile if a class is an abstraction providing a service you have to think more carefully about what equality means, or if it's even relevant to your class. For example imagine a Crawler class which can crawl websites and return a list of pages. What would equality mean for such a class? You'd rarely have two instances of a Crawler, and if you did, why would you compare them?
with blocks
with blocks provides a convenient way to copy an object and update specific fields. However this is always safe if the object has no identity, as copying it doesn't lose any information. Copying a mutable class loses the identity of the original object, as updating the copy won't update the original. As such you have to consider whether this really makes sense for your class.
ToString
The generated ToString prints out the values of all public properties. If your class is entirely defined by the properties it contains, then this makes a lot of sense. However if your class is not, then that's not necessarily the information you are interested in. A Crawler for example may have no public fields at all, but the private fields are likely to be highly relevant to its behavior. You'll probably want to define ToString yourself for such classes.
All properties of a record are per default public
All properties of a record are per default immutable
By default, I mean when using the simple record definition syntax.
Also, records can only derive from records and you cannot derive a regular class from a record.

Spring Data JPA 2.0.0: How to best resolve conflict between custom findById method and new version in CrudRepository?

Release 2.0.0 of Spring Data JPA replaced the findOne and exists methods with findById and existsById in CrudRepository.
We have the unfortunate situation where our entities PK attribute are called "oid", and often there is an additional natural id field named "id". To make matters worse both are Strings.
This means that our existing findById and existsById Repository methods conflict or inadvertently override those in CrudRepository.
The findById we can rename to queryById, and the existsById we can rename to something like existsLocalById, but both are workarounds and I suspect bugs will be introduced by people inadvertently using the wrong method.
Are there any other options available which would result in a cleaner design?
So a little digging into the JIRA behind the change reveals the following:
it should work if you annotate the method with #Query as that
indicates you want this thing to be a query method explicitly
Initial testing appears to show that this works as expected, e.g. In MyEntityRepository..
#Query
Optional<MyEntity> findById(String id);
#Query
boolean existsById(String id);
We'll still have to take care that the correct method is used as it could lead to some hard-to-determine bugs I suspect.

OData REST API where table has columns unique to customer

We would like to create an OData REST API. Our data model is such that each customer has their own database. All database objects have the same definition across all customer databases, with the exception of a single table.
The customer specific table we will call Contact. When a customer adds a column the system creates a column with a standardised name with a definition translated from options selected by the user in the UI. The user only refers to the column data by a field name they have specified to enable the user to be able to generate friendly queries.
It seems to me that the following approaches could be used to enable OData for the model described:
1) Create an OData open type to cater for the dynamic properties. This has the disadvantage of user requests for a customer not providing an indication of the dynamic properties that can be queried against. Even though they will be known for the user (via token authentication). Also, because dynamic properties are a dictionary, some data pivoting and inefficient query writing would be required. Not sure how to implement the IQueryable handling of query options for the dynamic properties to enable our own custom field querying.
2) Create a POCO class with e.g. 50 properties; CustomField1, CustomField2... Then somehow control which fields are exposed for use in OData calls. We would then include a separate API call to expose the custom field mapping. E.g. custom field friendly name of MobileNumber = CustomField12.
3) At runtime, check to see if column definitions of table changed since last check. If have, generate class specific to customer using CodeDom and register it with OData. Aiming for a unique URL for each customer. E.g. http://domain.name/{customer guid}/odata
I think the ideal for us is option 2. However, the fact the CustomField1 could be an underlying SQL data type of nvarchar, int, decimal, datetime, etc, there are added complications.
Has anyone a working example of how to achieve what has been described, satisfactorily?
Thanks in advance for any help.
Rik
We have run into a similar situation but with our entire dataset being unknown until runtime. Using the ODataConventionModelBuilder and EdmModel classes, you can add properties dynamically to the model at runtime.
I'm not sure whether you will have to manually add all of the properties for this object type even though only some of them are unknown or whether you can add your main object and then add your dynamic ones afterwards, but I guess either would be workable.
If you can get hold of which type of user it is on the server, you could then add only the properties that you are interested in (like option 3 but not having to CodeDom).
There is an example of this kind of untyped OData server in the OData samples here that should get you started: https://github.com/OData/ODataSamples/tree/master/WebApi/v4/ODataUntypedSample
The research we carried out actually posed Option 1 as the most suitable approach for some operations. i.e. Create an SQL view that unpivots the data in a table to a key/value pair of column name/column value for each column in the table. This was suitable for queries returning small datasets. This was far less effort than Option 3 and less confusing for the user than Option 2. The unpivot query converted the field values to nvarchar (string) values and thus meant that filtering in the UI by column value data types was not simple to achieve. (If we decide to implement this ability, I believe this can be achieved by creating a custom attribute that derives from EnablQueryAttribute, marking the controller action with it and manipulate the IQueryable before execution).
However, we wanted to expose a /Contacts/Export endpoint that when called would output the columns from a table with a fixed schema joined on a table with a client specific schema and output to a CSV file. All the while utilising the OData supported filter syntax. One of our customer databases has more than 12 million rows of data and is made up of approximately 30 columns.
To achieve this it looks like our best bet would have been to work with the Microsoft.OData.Core.UriParser.UriQueryExpressionParser class, unfortunately Microsoft in their wisdom have declared this as internal, as well as many of it's dependants.
Walking an abstract syntax tree built from OData supported query options and applying our own visitor to each node to build some dynamic Linq query/SQL seems like a possible solution.
For the time-being we will simply implement a cut-down set of supported $filter criteria without the support for grouping parenthesis.

Combining Spring Data query builder with Spring Data JPA Specifications?

Spring Data allows you to declare methods like findByLastname() in your repository interface and it generates the queries from the method name automatically for you.
Is it possible to somehow have these automatically-generated queries also accept a Specification, so that additional restrictions can be made on the data before it's returned?
That way, I could for example call findByLastname("Ted", isGovernmentWorker()), which would find all users that have the last name Ted AND who satisfy the isGovernmentWorker() specification.
I need this because I'd like the automated query creation provided by Spring Data and because I still need to be able to apply arbitrary specifications at runtime.
There is no such feature. Specifications can only be applied on JpaSpecificationExecutor operations.
Update
The data access operations are generated by a proxy. Thus if we want to group the operations (as in findByName + Criteria) in a single SELECT call, the proxy must understand and support this kind of usage; which it does not.
The intended usage, when employing Specification API would look like this for your case:
findAll(Specifications.where(hasLastName("Ted")).and(isGovernmentWorker())
Spring data allows you to implement custom repository and use Specifications or QueryDSL.
Please see this article.
So at the end you will have one YourCustomerRepository and appropriate YourRepositoryImpl implementation, where you will put your findByLastname("Ted", isGovernmentWorker()) method.
And then YourRepository should extend YourCustomerRepository interface.

JPA 2.0 Eclipselink OrderColumn support

I was reading over the docs regarding Eclipselink's support for #OrderColumn. It looks like this only applies to List and not Set. The reason I ask is because I have a ManyToMany bi-directional relationship (using a join table) which is a Set and is implemented with a HashSet because the collection can't have duplicates.
I wanted to order the entries in this set using #OrderColumn, but it appears I can only apply this to List, however using List will break my unique requirement. Is this understanding correct?
If so what is the recommended strategy for this case?
Thanks,
-Noah
This looks similar to the following question:
Why cannot a JPA mapping attribute be a LinkedHashset?
The Set interface does not define ordering of elements, so your set needs to be a concrete implementation like a TreeSet or LinkedHashSet implementation, not just any old Set. But your JPA provider is generally going to use its own collection implementations with special magic to handle lazy loading.
The above answer suggests that there may be some EclipseLink-specific workaround if you are willing to give up lazy loading.
I can think of two options, neither one perfect:
just use a List and rely on business logic to enforce uniqueness, with DB UNIQUE constraints as a backstop. Honestly, I end up using List for collections almost reflexively, even when Set would have been more appropriate; I admit it's sloppy but has yet to cause any significant problems for me in years of practice.
use a Set and change #ManyToMany to #OneToMany, and make your join table w/order column an actual entity that implements Comparable using the order column. Then, overload your getter method to do something like
if (! this.set instanceof TreeSet)
this.set = new TreeSet<T>(this.set);
return this.set;