Repository findIn confusion - spring-data

My database has an Exchanges class which contains a list of CurrencyPairs.
Is it possible to use to use a Repository method to directly obtain a CurrencyPair which matches on name within a given Exchange? I'm thinking of something like
CurrencyPairDbo findByExchangeNameAndCurrencyPairIn(...)
but I can't see quite how to tie it all together. Or do I need to write a custom query for this? And does this need to be in the ExchangeRepository or the CurrencyPairRespository?
#Entity()
#Table(name = "Exchanges")
public class ExchangeDbo {
#Id #GeneratedValue
#Getter private Long id;
#Getter private String exchangeName;
#OneToMany(mappedBy = "exchange",
cascade = CascadeType.ALL,
orphanRemoval = true,
fetch = FetchType.EAGER)
#BatchSize(size=100)
#Getter private List<CurrencyPairDbo> listCurrencyPair = new ArrayList<>();
...
}
#Entity()
public class CurrencyPairDbo {
#Id #GeneratedValue
#Getter private Long id;
#Column(unique=true)
private String currencyPair;
#ManyToOne(fetch=FetchType.EAGER)
#Getter private ExchangeDbo exchange;
...
}
Edit:
I'm thinking it's not Find...In that I want at all. I think that something like:
List<CurrencyPairDbo> x = exchangeRepository.findByExchangeNameLowercaseAndListCurrencyPairCurrencyPair(exchangeName.toLowerCase(), currencyPair);
might work, except that in returns an Exchange object and a:
org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [biz.ianw.coindatabase.database.ExchangeDbo] to type [biz.ianw.coindatabase.database.CurrencyPairDbo]

This, in the currency pair repository, seems to do the job.
I added a lower case field for matching purposes and an index for efficiency.
CurrencyPairDbo findByExchangeExchangeNameLowercaseAndCurrencyPairNameLowercase( String exchangeName, String currencyPair );

Related

Querying revisions of nested object using spring-data-envers

I'm trying to implement entity auditing in my Java Spring Boot project using spring-data-envers. All the entities are being created as they should, but I've come up against a brick wall when executing the query.
parentRepository.findRevisions(id).stream().map(Parent::getEntity).collect(Collectors.toList());
During this select the repository is supposed to fetch info also from the child entity, instead I get unable to find <child object> with {id}.
According to my experiments categoryId is being searched in the Category_Aud table, instead of the actual table with desired data.
Code snippets:
#Data
#Entity
#Audited
#NoArgsConstructor
public class Parent {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Enumerated(EnumType.STRING)
private Status status;
#Enumerated(EnumType.STRING)
private Type requestType;
private String fullName;
#ManyToOne
#JoinColumn(name = "child_id")
private Child child;
}
#Data
#Entity
#Audited
#NoArgsConstructor
public class Child {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String description;
}
I've extended Parent with RevisionRepository
#Repository
public interface ParentRepository extends RevisionRepository<Parent, Long, Long>, JpaRepository<Parent, Long>
And annotated my SpringBootApplication entry class with:
#EnableJpaRepositories(repositoryFactoryBeanClass = EnversRevisionRepositoryFactoryBean.class)
I couldn't find any explanation for this so far, how can make parentRepository get what I need?
The underlying problem here is that the reference from a versioned entity isn't really properly defined. Which variant of the reference should be returned? The one at the start of the version you use as a basis, the one at the end? The one that exists right now?
There are scenarios for which each variant makes sense.
Therefor you have to query the revisions yourself and can't simply navigate to them.

How to auto generate id using MongoDB and Spring Data MongoDB?

I need to auto generate the id on my documents for persist on database. But if i don't set the id it has an error that cannot be null. How could I generate the id for reduce the repeated code and make it simple?
#Id
private ObjectId id;I found a solution that is,
must the type of the id be an org.bson.types.ObjectId, like above:
#ToString
#Getter
#NoArgsConstructor
#RequiredArgsConstructor(staticName = "of")
public class Guide {
#Id
private ObjectId id;
#NonNull
private String name;
}
The right place that are the solution is:
#Id private ObjectId id;

Hibernate map List<Enums> to Postgres enum

I need to map a list of Enums to a table in postgres.
For the generic mapping of a 1:1 relation I found this post very helpful. The code looks like:
#Entity(name = "Post")
#Table(name = "post")
#TypeDef(
name = "pgsql_enum",
typeClass = PostgreSQLEnumType.class
)
public static class Post {
#Id
private Long id;
private String title;
#Enumerated(EnumType.STRING)
#Column(columnDefinition = "post_status_info")
#Type( type = "pgsql_enum" )
private PostStatus status;
//Getters and setters omitted for brevity
}
But I have no troubles to figure out a solution if PostStatus is a List<PostStatus>. Because than the definition fails.
To make it specific: I have a table, e.g. PostRelations where I can store post_id and status. For the sake of sample I can store multiple status (e.g. timebased). So how to define it properly if I have
#Entity(name = "Post")
#Table(name = "post")
public static class Post {
#Id
private Long id;
private String title;
private List<PostStatus> status;
}
The approach to define it the same way cause an exception (which seems clear because the annotation is for a enum and not for a List)
Caused by: java.lang.ClassCastException: interface java.util.List
at java.lang.Class.asSubclass(Class.java:3404) ~[na:1.8.0_212]
at org.hibernate.type.EnumType.setParameterValues(EnumType.java:86) ~[hibernate-core-5.3.10.Final.jar:5.3.10.Final]
After some research and digging into the issue I finally solved the problem thanks to the sample for proper linking and setup:
#ElementCollection
#CollectionTable(name = "post_permission", joinColumns = #JoinColumn(name = "post_id"))
private List<PostStatus4Save> status;
and a thin wrapper around the existing enum PostStatus
#Embeddable
#Data //lombok
#TypeDef(name = "pgsql_enum", typeClass = PostgreSQLEnumType.class)
#AllArgsConstructor //lombok
#NoArgsConstructor //lombok
public class PostStatus4Save {
#Enumerated(EnumType.STRING)
#Type(type = "pgsql_enum")
PostStatus postPermission;
}

Set vs List in REST One To Many

I have one to many relationship. If in class Customer I write List:
private List<Orders> order;
my GetMapping will work fine.
But I want to use best practices and I write Set instead of List:
private Set<Orders> order;
In result I have error:
Could not write JSON: Infinite recursion (StackOverflowError); nested
exception is com.fasterxml.jackson.databind.JsonMappingException:
Infinite recursion (StackOverflowError)
Why I have this error? What's wrong with Set?
My entities:
#Entity
public class Customer {
#Id
#GeneratedValue
private int id;
private String firstName;
private String lastName;
#OneToMany(cascade=ALL, mappedBy="customer", orphanRemoval=true)
private Set<Orders> order;
//private List<Orders> order;
}
#Entity
public class Orders {
#Id
#GeneratedValue
private int id;
#JsonIgnore
#ManyToOne
#JoinColumn(name="customer_id", nullable=false)
private Customer customer;
}
And GetMapping:
#GetMapping("/customer/{id}")
public ResponseEntity get(#PathVariable Long id) {
Optional<Customer> customer = customerRepository.findById(id);
return new ResponseEntity<>(new ResponseObject(customer));
}
UPD. I see question Infinite Recursion with Jackson JSON and Hibernate JPA issue. But it's other question. I talk about difference in use List and Set. I am not interesting in #JsonIgnore and I don't ask about it (and I use it in my code). I want to understand why I have an error when I use Set and don't have error with List

Why am I getting "Duplicate entry" errors for related objects upon merge in eclipselink?

I have an entity class that contains a map of key-value pairs which live in a different table and there may be no such pairs for a given entity. The relevant code for the entity classes is below.
Now, when I insert such an entity with persist(), then add key-value pairs, and then save it with merge(), I get duplicate entry errors for the related table that stores the key-value pairs. I tried to hold back insertion until the keys were added, to have one call to persist() only. This led to duplicate entry errors containing an empty (zero) id in the foreign key column (ixSource).
I followed the process in the debugger, and found that eclipselink seems to be confused about the cascading. While it is updating the entity, it executes calls that update the related table. Nonetheless, it also adds those operations to a queue that is processed afterwards, which is when the duplicate entry errors occur. I have tried CascadeType.ALL and MERGE, with no difference.
I'm using static weaving, if it matters.
Here's the entities`code, shortened for brevity:
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
#DiscriminatorColumn(name = "sType")
#Table(name = "BaseEntity")
public abstract class BaseEntity extends AbstractModel
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ix")
private long _ix;
}
#Entity
#Table(name = "Source")
public class Source extends BaseEntity
{
#OneToMany(cascade = CascadeType.MERGE)
#JoinTable(name = "SourceProperty", joinColumns = { #JoinColumn(name = "ixSource") })
#MapKey(name = "sKey")
private Map<String, SourceProperty> _mpKeys;
// ... there's more columns that probably don't matter ...
}
#Entity
#Table(name = "SourceProperty")
#IdClass(SourcePropertyKey.class)
public class SourceProperty
{
#Id
#Column(name = "sKey", nullable = false)
public String sKey;
#Id
#Column(name = "ixSource", nullable = false)
public long ixSource;
#Column(name = "sValue", nullable = true)
public String sValue;
}
public class SourcePropertyKey implements Serializable
{
private final static long serialVersionUID = 1L;
public String sKey;
public long ixSource;
#Override
public boolean equals(Object obj)
{
if (obj instanceof SourcePropertyKey) {
return this.sKey.equals(((SourcePropertyKey) obj).sKey)
&& this.ixSource == ((SourcePropertyKey) obj).ixSource;
} else {
return false;
}
}
}
I can't see how those errors would occur. Could you include the SQL and ful exception.
What version of EclipseLink are you using, did you try the latest release?
Why are you calling merge? Are you detaching the objects through serialization, if it is the same object, you do not need to call merge.
It could be an issue with the #MapKey, does it work if you remove this?