Column that are combinations of other columns on JPA's entity - spring

My example is,
#Entity
#Getter
#Setter
public class MyEntity {
private String A;
private String B;
#JsonIgnore #Column(unique = true)
private String C;
public String getC() {
return this.A + "_" + this.B;
}
public void setC(String C) {
this.C = this.A + "_" + this.B;
}
}
i want to combine at C by A + B strings.
because it's my unique key for something useful.
(ps,
In fact, I should be the only A + B combination. If you have any other suggestion, I would like to recommend it.)
my POST request example is,
"A" : "value A",
"B" : "value B"
without C like above.
so i tried change at getter and setter to return A+B;
but it didn't work.(C is null)
what should i do???

Thanks to #M.Deinum I solved it by using
#Table(uniqueConstraints=#UniqueConstraint(columnNames = {"A", "B"}))

Related

How getting all properties (Parent and child class) in spring boot

I'm new in spring boot
How can i do to get all properties
coming from client(Postman) json in spring
boot?
For exemple i have classe
Class A{
String a;
}
Classe B extens A{
String b;
}
Class C {
long id;
List<B> c=new arraylist<>();
}
In my controller
#Postmaping()
test(#Requestbody C c){
Sysout(c);// I want get all properties a and b
}
i only got the b properties not a
My json
{ "id":1, "c":[{"a":"a","b":"b"}] }
In your example you have Class B extending from Class A. Therefore B is more specific. If your RequestBody contains string a and string b
{
"a":"valueA",
"b":"valueB"
}
you have to change your request Body to receive Class B.
#PostMapping("/some/endpoint)
public void test(#Requestbody B b){
System.out.println(b); // contains valueA and valueB
}
After a hard debugging match, I just realized that I was wrong #Override the toString() method of the child class.
It was simply necessary to add super.toString() to child class
#Override
public String toString() {
return super.toString() +
"b ='" + b+ '\'' +
'}';
}

MapStruct exclude LOT of fields from mapper

Suppose I have a complex entity like the follow:
class A {
private String a;
private String b;
private String c;
/**
* so on */
private B bb;
private C cc;
}
and the respective DTO:
class ADTO {
private String a;
private String b;
private String c;
/**
* so on */
private BDTO bb;
private CDTO cc;
}
Now suppose C entity (and CDTO) has many variables and I want map is with just his ID field. For example
#Mapper(componentModel = "spring")
public Interface AMapper {
BDTO bToDto(B b);
B bFromDto(BDTO bDto);
CDTO cToDto(C c); // for this I want to map just the id!!
C cFromDto(CDTO cDto); // even for this
}
How can I do?? I wouldn't write 50 times #Mapper(properties = "someField", ignore = true), is there another method??
Thank you
You can create a separate mapper for C class and add in AMapper class using uses field of #Mapper
#Mapper(componentModel = "spring", uses={"CMapper.class"})
public Interface AMapper {
BDTO bToDto(B b);
B bFromDto(BDTO bDto);
// remove below
// CDTO cToDto(C c);
// C cFromDto(CDTO cDto);
}
public CMapper{
public C fromDTO(CDTO) {
// add mapping for ID only
}
public CDTO toDTO(C) {
// add mapping for ID only
}
}

spring-data-mongodb aggregation with composite ID

I'm having trouble reading documents from MongoDB using the aggregation framework: I always get null IDs in my results. This only happens for documents that have composite IDs. I tried various versions of spring-data-mongodb (1.10.12, 2.0.7), same result.
Entity definition class
#Document(collection="entities")
public class MyEntity {
static class CompositeKey implements Serializable {
private String stringKey;
private Integer intKey;
public CompositeKey(String stringKey, Integer intKey) {
this.stringKey = stringKey;
this.intKey = intKey;
}
public Integer getIntKey() {
return intKey;
}
public String getStringKey() {
return stringKey;
}
public String toString() {
return "{" + stringKey + " - " + intKey + "}";
}
}
#Id
private CompositeKey id;
private String param;
public MyEntity() {}
public MyEntity(String stringKey, Integer intKey) {
id = new CompositeKey(stringKey, intKey);
}
public CompositeKey getId(){
return id;
}
public void setId(CompositeKey id) {
this.id = id;
}
public String getParam() {
return param;
}
public void setParam(String param) {
this.param = param;
}
}
Testing code
public static void main(String[] args) {
MongoClient client = new MongoClient("127.0.0.1");
SimpleMongoDbFactory factory = new SimpleMongoDbFactory(client, "aggTest");
MongoTemplate mongoTemplate = new MongoTemplate(factory);
MyEntity entity = new MyEntity();
entity.setId(new MyEntity.CompositeKey("one", 1));
entity.setParam("param1");
mongoTemplate.save(entity);
entity = new MyEntity();
entity.setId(new MyEntity.CompositeKey("two", 2));
entity.setParam("param2");
mongoTemplate.save(entity);
Criteria crit = Criteria.where("param").ne("param3");
List<AggregationOperation> aggOpList = new ArrayList<AggregationOperation>();
aggOpList.add(Aggregation.match(crit));
System.out.println("Documents fetched with find: ");
for (MyEntity aggResult : mongoTemplate.find(new Query(crit), MyEntity.class).toArray(new MyEntity[0]))
System.out.println(aggResult.getId() + " - " + aggResult.getParam());
System.out.println("\nDocuments fetched with aggregate: ");
TypedAggregation<MyEntity> aggregation = new TypedAggregation<>(MyEntity.class, aggOpList);
AggregationResults<MyEntity> aggregate = mongoTemplate.aggregate(aggregation, MyEntity.class);
for (MyEntity aggResult : aggregate.getMappedResults())
System.out.println(aggResult.getId() + " - " + aggResult.getParam());
}
Output
Documents fetched with find:
{one - 1} - param1
{two - 2} - param2
Documents fetched with aggregate:
null - param1
null - param2
Debugging into the following method MappingMongoConverter.read(final MongoPersistentEntity entity, final Document bson, final ObjectPath path) I found that in the first case (find method) the documentAccessor variable has the following contents
Document{{_id=Document{{stringKey=one, intKey=1}}, param=param1, _class=MyEntity}}
whereas in the second case (aggregation query) it looks like
Document{{stringKey=one, intKey=1, param=param1, _class=MyEntity}}
The document gets flattened somehow, which makes it impossible for the converter to populate the ID field. I must be doing something wrong, but what?
Spring Data MongoDB lower than 3.x automatically flatten composite id (fields under composite id are unwrapped and place at root object). This is removed in version 3.0 onwards:
https://docs.spring.io/spring-data/mongodb/docs/current/reference/html/#new-features.3.0

Jest mapping with getSourceAsObjectList()

I tried to map elastic data to list. since getSourceAsObjectList() method is deprecated, I made code like this.
class activityObj {
private String name;
private String oid;
public String getName()
{
return name;
}
public void setName( String name)
{
this.name = name;
}
public String getOid()
{
return oid;
}
public void setOid( String oid)
{
this.oid = oid;
}
}
List< Hit<activityObj, Void>> hits = result.getHits(activityObj.class);
List< activityObj> list = new ArrayList<activityObj>();
for (SearchResult.Hit<activityObj, Void> hit: hits) {
activityObj objectSource = hit.source; // null point error
list.add(objectSource);
logger.info( "hits : " + objectSource.getName());
}
It doesn't work as I expect and looks messy ( it's using two list value to map result). Am I doing wrong?
Michael's answer helped me and is a nice way to do it. Here's what I came up with including all the parts I used to make the query and get the result.
In my case I wanted to get a list of user ids collected from the source of each document in the result.
class DocSource {
private Integer userId;
public Integer getUserId() {
return userId;
}
}
String query = "{\n"
+ " \"_source\": [\n"
+ " \"userId\"\n"
+ " ],\n"
+ " \"query\": {\n"
+ " <some query config here>"
+ " }\n"
+ " }\n"
+ "}";
Search search = new Search.Builder(query)
.addIndex("my-index")
.build();
SearchResult result = jestClient.execute(search);
List<SearchResult.Hit<DocSource, Void>> hits = result.getHits(DocSource.class);
List<Integer> listOfIds = hits.stream()
.map(h -> h.source.getUserId())
.collect(Collectors.toList());
Have you tried something like this:
List< activityObj> list = hits.stream().map(h -> h.source).collect(Collectors.toList());

How to sort JPA entities using TreeSet

I have a few entity beans with sets of other entities as attributes. I want to sort them and guarantee that at every insertion they will remain sorted.
I tried this way:
#Entity
#Table(name = "Document")
public class Document implements Serializable, Comparable<Document> {
...
#ManyToOne
private Project relativeProject;
...
#Override
public int compareTo(Document d) {
long data1 = getDate().getTimeInMillis();
long data2 = d.getDate().getTimeInMillis();
if(data1 > data2)
return 1;
else
if(data2 < data1)
return -1;
else
return 0;
}
#Override
public boolean equals(Object d) {
return (getIdDocument() == ((Document)d).getIdDocument());
}
#Override
public int hashCode() {
return Long.valueOf(getIdDocument()).hashCode();
}
}
#Entity
#Table(name="Project")
public class Project implements Serializable, Comparable<Project> {
...
#OneToMany(mappedBy="relativeProject", fetch = FetchType.EAGER)
#Sort(type = SortType.NATURAL)
private SortedSet<Document> formedByDocuments;
public Progetto() {
this.formedByDocuments = new TreeSet<Document>();
}
...
}
But it does not work. The problem is that, even if in the database there are all needed entries, when a session bean returns a Project there will miss some Document. Moreover, entries are not sorted at all in the database.
If I do not sort at all (using HashSet) and republish the project, everything works fine and I get all the elements in a set (but not sorted, of course).
Can someone help me to find out what's wrong with my sorting?
I'm assuming getIdDocument() returns an object and not a primitive.
In that case, you need to use equals and not ==
public boolean equals(Object d) {
return (getIdDocument().equals((Document)d).getIdDocument());
}
Edit:
Looks like the problem is in the second if(data2 < data1) statement of the compareTo() method. This should be if(data1 < data2)

Resources