findById() gives No property Id found - spring

I have three entities.
(I am using xxx as a place holder for this example)
I have set up all their #Entities with
#Entity
#Table(name = "xxx")
public class xxx {
#Id
#Column(name = "xxx_id")
int xxx_id;
However, I am able to do:
findById(int ...) for only ONE of the entities in their respective Repository.
When I try to do that for the other two entities, I get this problem:
"Invalid derived query! No property id found for type xxx!"
I am able to run it and get the proper results. But why am I getting this error for two entities but not the other?
I set up the entities and their repositories exactly the same way.
The ONLY difference is that in the entity whose repository does not return any errors, I am joining that entity with another entity whose repository fails, but I used "mappedBy" in the #JoinColumns section.
Could that have something to do with why that one has no problems?

How findBy... works?
Entity:
private int clientid;
private String firstname;
private String lastname;
Query:
findBy<Name_as_per_entity>
findByClientid(int clientid);
findByFirstnameAndLastname(String firstname, String lastname)
Solution
Because we treat the underscore character as a reserved character, we
strongly advise following standard Java naming conventions (that is,
not using underscores in property names but using camel case instead).
Doc
The underscore _ is a reserved character in Spring Data query derivation to potentially allow manual property path description.
Stick to the Java naming conventions of using camel-case for member variable names and everything will work as expected.
Also Refer this

Related

Same entity for two different aggregate

My schema will be something similar to the above picture.
I am planning to use Spring data JDBC and found that
If multiple aggregates reference the same entity, that entity can’t be part of those aggregates referencing it since it only can be part of exactly one aggregate.
Following are my questions:
How to create two different aggregates for the above without changing the DB design?
How to retrieve the Order / Vendor list alone? i.e. I don't want to traverse through the aggregate root.
How to create two different aggregates for the above without changing the DB design?
I think you simply have three Aggregates here: Order, Vendor and ProductType. A mental test that I always use is:
If A has a reference to B and I delete an A, should I automatically and without exception delete all Bs referenced by that A? If so B is part of the A Aggregate.
This doesn't seem to be true for any of the relationships in your diagram, so let's go with separate Aggregates for each entity.
This in turn makes each reference in the diagram one between different Aggregates.
As described in "Spring Data JDBC, References, and Aggregates" these must be modelled as ids in your Java code, not as Java references.
class Order {
#Id
Long orderid;
String name;
String description;
Instance created;
Long productTypeId;
}
class Vendor {
#Id
Long vid;
String name;
String description;
Instance created;
Long productTypeId;
}
class ProductType {
#Id
Long pid;
String name;
String description;
Instance created;
}
Since they are separate Aggregates each gets it's own Repository.
interface Orders extends CrudRepository<Order, Long>{
}
interface Vendors extends CrudRepository<Vendor, Long>{}
interface ProductTypes extends CrudRepository<ProductType, Long>{}
At this point I think we fulfilled your requirements. You might have to add some #Column and #Table annotations to get the exact names you want or provide a NamingStrategy.
You probably also want some kind of caching for the product types since I'd expect they see lots of reads with only few writes.
And of course you can add additional methods to the repositories, for example:
interface Orders extends CrudRepository<Order, Long>{
List<Orders> findByProductTypeId(Long productTypeId);
}

Spring Data JPA - How to find by param with underscore

Here is my model:
public class Log {
#Id
private String id;
private String project;
private String test_no;
// Constructor, getters and setters.
}
How can I add a findBy query which allows me to finding an element by its test_no value? I have tried those method headers but they don't work:
List<Log> findByTest_No(String test_no);
The error that my STS reports is: Invalid delivery query! No property test found in type Log!
List<Log> findByTest_no(String test_no);
The error that my STS reports is: Invalid delivery query! No property test found in type Log!
List<Log> findByTestno(String test_no);
The error that my STS reports is: Invalid derived query! No property testno found for type Log! Did you mean 'test_no'?
It seems that _ is a special character which separates properties names
... it is possible for the algorithm to select the wrong property ... To resolve this ambiguity you can use \_ inside your method name to manually define traversal points ...
Docs
So it can't find test field in Log class.
Try to use:
#Query("select log from Log log where log.test_no = ?1")
List<Log> findByTestNo(String testNo);
There is no need to use private String test_no; You may use private String testNo; Spring automatically understand that you are binding test_no column in the database. Also you can use
#Column(name = "test_no")
private String testNo;
After this changes you can execute queries, mentioned in your question without any custom sql.
List<Log> findByTestNo(String testNo);

Spring JPA repository how to write a query

I have a User class, that is identified by id, and Skills class, that has its own id field, and also references User.
public class User {
#Id
#GeneratedValue
private int id;
#JsonIgnore
#OneToOne(mappedBy = "user")
private SoftSkills softSkills;
}
the other one has
#Entity
public class SoftSkills {
#Id
#GeneratedValue
private int id;
#OneToOne
#JoinColumn
private User user;
}
Is there a simple way to write a query, implementing the JPARepository, that would search the SoftSkills class by using user.id field as a parameter and return a SoftSkills object as a result?
You can, from the documentation:
Property expressions can refer only to a direct property of the managed entity, as shown in the preceding example. At query creation time you already make sure that the parsed property is a property of the managed domain class. However, you can also define constraints by traversing nested properties. Assume a Person has an Address with a ZipCode. In that case a method name of
List<Person> findByAddressZipCode(ZipCode zipCode);
creates the property traversal x.address.zipCode. The resolution algorithm starts with interpreting the entire part (AddressZipCode) as the property and checks the domain class for a property with that name (uncapitalized). If the algorithm succeeds it uses that property. If not, the algorithm splits up the source at the camel case parts from the right side into a head and a tail and tries to find the corresponding property, in our example, AddressZip and Code. If the algorithm finds a property with that head it takes the tail and continue building the tree down from there, splitting the tail up in the way just described. If the first split does not match, the algorithm move the split point to the left (Address, ZipCode) and continues.
So this will do the trick:
SoftSkills findByUserId(int id);
Reference; Spring Data JPA Documentation

spring data rest hateoas dynamically hide repository

I'm still trying to figure what exactly it is I am asking but this is fallout from a discussion in the office. So the dilemma is that on a mapping set to eager with a repository defined for the entity the mapping is to, a link is produced. Some of the time that is fine but some of the time I'd rather have the object fetched itself. If there is not a repository defined for that entity then that is what will occur with the eager fetch strategy. What would be ideal is if I could pass in a parameter and have the existence of that repository disappear or reappear.
Not totally following, but either the repo exists or not. If you want to be able to access entities of type X independently of other entity types, then you have to define a repo for type X.
I think you could achieve something similar using projections.
So you define define a repository for your association entity. By default spring data rest will just render a link to this entity and not embed it in the response.
Then you define a projection with a getter for your associated entity. You can choose on the client side if you want the projection by adding the projection query parameter.
So lets say you have a person with an address - an exported repository exists for Person and Address:
#Entity
public class Person {
#Id #GeneratedValue
private Long id;
private String firstName, lastName;
#OneToOne
private Address address;
…
}
interface PersonRepository extends CrudRepository<Person, Long> {}
interface AddressRepository extends CrudRepository<Address, Long> {}
Your projection could look like this:
#Projection(name = "inlineAddress", types = { Person.class })
interface InlineAddress {
String getFirstName();
String getLastName();
Address getAddress();
}
And if you call http://localhost/persons/1?projection=inlineAddress you have the address embedded - and by default it is just linked.

Multiple Relationship classes with the same type

Using spring-data-neo4j, I want to create two classes using #RelationshipEntity(type="OWNS") to link a Person class to both a Pet and Car.
#RelationshipEntity(type="OWNS")
public class OwnsCar {
#Indexed
private String name;
#StartNode
private Person person;
#EndNode
private Car car;
}
#RelationshipEntity(type="OWNS")
public class OwnsPet {
#Indexed
private String name;
#EndNode
private Person person;
#StartNode
private Pet pet;
}
This saves to the Graph Database properly with no problems, as I can query the actual Node and Relationship and see they type, etc.
But when I attempt to use #RelatedTo(type="OWNS", elementClass=Pet.class) I either get a class cast exception, or when using lazy-initialization I get incorrect results.
#NodeEntity
public class Person {
#Indexed
private String name;
#RelatedTo(type="OWNS", direction=Direction.OUTGOING, elementClass=Pet.class)
private Set<Pet> pets;
#RelatedTo(type="OWNS", direction=Direction.OUTGOING, elementClass=Car.class)
private Set<Car> cars;
}
The result I get when I attempt to print our my person(my toString() has been omitted, but it simply calls the toString() for each field) is this:
Person [nodeId=1, name=Nick, pets=[Car [nodeId=3, name=Thunderbird]], cars=[Car [nodeId=3, name=Thunderbird]]]
Does anyone know if this can be done, should be done, is just a bug or a feature that is missing?
It seems like the problem is, that the annotation causes springDataNeo4j to priorize the relationship name. I tried the same on another sample I created. If both annotations contain
type="OWNS" it mixes both 'objects'. When I omit this information, and only use direction and type, it works for me.
Unfortunately this will lead to a problem if you are using another #RelatedTo annotation with more Pets or Cars related with another annotation. As it would not differ between "OWNS" and any other relation to a Pet-Type, the set returns all related pets (example: peter ->(HATES-Relationsip)->dogs).
If it's a bug or not, I can't tell... But for the database: There are only nodes and relations. Both are not typed, so neo4j does not know anything about your 'Pet'- or 'Car'-Class. Spring data neo4j handles this, either by indexing all nodes per type and setting a type-attribute, or using a specific graph-layout (with subreferences). Even if you would want to fetch all pets of a person with a traversal description, you would have so much more code to write, since the outgoing relations with name 'OWNS' contains two types of objects.
I would recommend using two different names. It's easier to write your custom traversals/queries later on, and its probably even faster as well, because no class-type comparison will be needed. Is there any reason, why you would need these specific names?
PS: It is possible, that not everything is 100% accurate. I don't know springdataneo4j in detail, but that's what I figured out so far.

Resources