JPA entity with column of type long that have a Null value - jpa

I'm new to JPA . I'm using spring data and I want to create an entity "File" (a folder is a File ) . each File can have a parent (or not).
this is my table's columns :id ,name,path ,mtime ,parentid.
I used this in my entities
#ManyToOne
#JoinColumn(name = "parentid")
private File parent;
public File() {}
public File(String name, String path,File parent) {
this.name = name;
this.path=path;
this.parent=parent;
}
#Override
public String toString() {
return String.format(
"File[ id=%d,name='%s', path='%s',parentid=%d]",
id,name, path,parent.id);
}
in my test I did this :
fileRepository.save(new File("file1","file1",null));
File file1=fileRepository.findOne((long) 1);
fileRepository.save(new File("file2","file2",file1));
and it inserted the first line with parentid NULL and a second line with parentid 1 (the first file).( I confirmed that on phpmyadmin)
I wanted to show the lines so i did this :
for (Object element : Lists.newArrayList(fileRepository.findAll())) {
System.out.println(element);
}
but it doesn't work .
when I removed parentid from my toString() function I get the correct result :
File[ id=1,name='file1', path='file1']
File[ id=2,name='file2', path='file2']
I get the same problem if I add a new column of type Long and when one of the lines have a NULL value in that column .
how Can I fix that ?

Your toString() method "doesn't work" because you're trying to get the id of a null parent, which obviously causes a NullPointerException. You need to test if the parent is null before trying to get and print its ID. Reading the message, type and stack trace of the exception would have allowed you to find this out. Using a debugger as well.
A variable of type long can't hold null. Primitive types are not nullable. So you need to use the type java.lang.Long for this field.

Related

JPQL Query - No constructor taking error?

I have a Card entity class with many columns.
I used dto because I want to get some columns from this Entity.
I created a DTO class and wrote a query to CardRepositoryCustom.
But when I try to run the Query I get various errors "No constructor taking".
My dto class:
#Data
#NoArgsConstructor
#AllArgsConstructor
public class CardDTO {
private String test1;
private String test2;
private String test3;
private String test4;
}
JPQL RepositoryCustom :
#Repository
#Transactional
public class CardRepositoryCustom {
public CardDTO test1() {
JpaResultMapper jpaResultMapper = new JpaResultMapper();
String q = "SELECT "+
" c.test1 "+
"FROM "+
" CardEntity c ";
Query query = entityManager.createQuery(q);
try {
return jpaResultMapper.uniqueResult(query, CardDTO.class);
} catch (NoResultException nre) {
return null;
}
}
}
Errors:
java.lang.RuntimeException: No constructor taking: java.lang.String
at org.qlrm.mapper.JpaResultMapper.findConstructor(JpaResultMapper.java:107) ~[qlrm-1.7.1.jar:na]
at org.qlrm.mapper.JpaResultMapper.uniqueResult(JpaResultMapper.java:64) ~[qlrm-1.7.1.jar:na]
at ....
I know how to fix this error.
You just need to write the following constructor in the DTO class as shown below.
public CardDTO(String test1) {
this.setTest1(test1);
}
Here I am curious, if I want test2, test3, test4 and write Query in Custom class, should there be as many constructors in DTO class as that number?
I think this method is really inefficient. Is there any solution I am not aware of?
This seems to be more about QLRM than JPA or Spring.
Judging from the error message the constructor has to match the arguments provided. Probably the easiest variant is to always provide all arguments, possibly with a value of null or some other literal.
The query in your example would then become.
SELECT c.test1, null, null, null FROM CardEntity c
Of course QLRM just provides a JpaResultMapper and it would probably not too difficult to provide your own, or offer a PR to QLRM that inspects names of the result set and tries to match them to parameter names or the constructor.

Why does EntityFramework populate my NotMapped field with a trash value

Hello i am retrieving a IEnumerable<Something> using Entity Framework and this Something has an IEnumerable<SomethingElse> property that has the attribute [NotMapped] over it.
Why does entity framework populate this IEnumerable<SomethingElse> field with some unknown object that is neither null but can't be interogated with Linq throwing the following exception:
System.ArgumentNullException: 'Value cannot be null. (Parameter 'source')'
public class Something
{
[NotMapped]
public IEnumerable<SomethingElse> Items{get;set;}
}
public struct SomethingElse
{
//some fields
}
Insertion:
When i insert the list some elements have the NotMapped field null, while others not:
List<Something> toBeInserted=new List<Something>{ new Something{Items=null},new Something{Items=new[]{ new SomethingElse{}}};
//dbcontext insert the list....
Retrieval
List<Something>somethings=(await this.[SomeDBContext].Somethings).ToList();
Now at retrieval some elements have the NotMapped property null as it should be,while someothers have this weird non-null IEnumerable<SomethingElse>d_6that throws exception on any Linq interogation:
var weirdElement=somethings.First();
weirdElement.Items.Count(); //throws
weirdElement.Items.Any();throws
P.S I have checked this post regarding computed properties and it says: Materialize the list when you fetch it from the database to resolve the computed properties.That is what i have done.
I issue (await this.DBContext.Somethings).ToList() to no avail.
Some Something's still have their IEnumerable<SomethingElse> property not null.
Later Edit
This is a picture with what the
not mapped property of the element looks like:
I am computing the IEnumerable<SomethingElse> using an extension method:
public class Extension
{
public static IEnumerable<SomethingElse> Compute(this IEnumerable<SomethingSomethingElse> someOthers){}
}
The name of the type of the field IEnumerable<SomethingElse> is <Compute>d_6

Saving value in Hibernate to another table than entity table

I have two tables bo_operator and hist_bo_operator_password. In bo_operator the id column is foreign key to hist_bo_operator_password and I can have many the same operator_id in hist_bo_operator_password and only one id in bo_operator.
My entity:
#Entity
#Table(name="bo_operator")
public class Operator implements Serializable
and that's how I am getting values from hist_bo_operator_password:
#ElementCollection
#CollectionTable(name="hist_bo_operator_password", joinColumns=#JoinColumn(name="id_operator"))
#Column(name="password")
public List<String> oldPasswords = new ArrayList<String>();
but when I'm trying to get only one value by:
#ElementCollection
#CollectionTable(name="hist_bo_operator_password", joinColumns=#JoinColumn(name="id_operator"))
#Column(name="password")
public String oldPassword;
I'm getting error:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.class]: Invocation of init method failed; nested exception is org.hibernate.AnnotationException: Illegal attempt to map a non collection as a #OneToMany, #ManyToMany or #CollectionOfElements: local.vlex.operator.model.Operator.oldPassword
and all I want to do is makeing an insert into hist_bo_operator_password by
operator.setOldPassword(oldPassword);. I think the problem is that it doesn't know which password take if there is many values for the same id.
How to achive it?
#Edit
I also tried:
#Table(name="bo_operator")
#SecondaryTable(name = "hist_bo_operator_password",pkJoinColumns=#PrimaryKeyJoinColumn(name="id_operator", referencedColumnName="id"))
I even found ORDER BY so:
#Column(name="password", table="hist_bo_operator_password")
#OrderBy("data_ins")
public String oldPassword;
but seems like there is no #Limit or something like this in JPA and I still have many values to the same id which cause error:
org.hibernate.HibernateException: Duplicate identifier in table for: [local.vlex.operator.model.Operator#1]
As you described at the first sentence you have one-to-many relationship
#ElementCollection
#CollectionTable(name="hist_bo_operator_password", joinColumns=#JoinColumn(name="id_operator"))
#Column(name="password")
#OrderBy("data_ins")
public List<String> oldPasswords = new ArrayList<String>();
Then add necessary getter
Optional<String> getPassword() {
return oldPasswords.size() > 0
? Optional.of(oldPasswords.get(0))
: Optional.empty();
}
And setter
void setPassword(String password) { // or maybe addPassword?
oldPasswords.add(password);
}
Why don't you create entity of hist_bo_operator_password?
Then you could have List of that entities (instead of just String List) and just add another object to List and save entity Operator.

Error: Parameter value did not match expected type

I am trying to retrieve a USER from my database using the ID in the WHERE clause. However I am receiving an error and my program is failing.
This is the error I'm receiving when I run my program:
ERROR [org.jboss.as.ejb3.invocation] (default task-19)
JBAS014134: EJB Invocation failed on component CustomerServiceBeanImpl
for method public abstract package.name.entity.ICustomer
package.name.bean.CustomerServiceBean.getCustomerById(long):
javax.ejb.EJBException: java.lang.IllegalArgumentException:
Parameter value [19533] did not match expected type [package.name.entity.User (n/a)]
Note: [19533] is a test value I used.
This is the method that is having the error in the CustomerServiceBeanImpl.java:
#Override
public Customer getCustomerById (final long id)
{
return Customer.getById (this.em, id);
}
This is the method that's being called by the component CustomerServiceBeanImpl:
public static Customer getById (final EntityManager em, final long id)
{
for (final Customer c : em.createNamedQuery ("Customer.getById", Customer.class)
.setParameter ("id", id).setMaxResults (1).getResultList ())
{
return c;
}
return null;
}
The name query is this:
#NamedQuery (name = "Customer.getById",
query = "SELECT o FROM gnf.Customer o WHERE o.user = :id")
In the Customer.java class itself the relevant column is this one:
#ManyToOne (fetch = FetchType.LAZY)
#JoinColumn (name = "user_id")
private User user;
Doing a quick check of my ERD the "id" column in my "customer" table has a data type of BIGINT. However I'm not sure if that matters. (PostgreSQL database by the way.)
How can I fix this error?
The WHERE clause in your named query seems to be the problem. The attribute user in your Customer.class is of type User and your query expects it to be a type compatible to long.
...
Parameter value [19533] did not match expected type [package.name.entity.User ...
So if you need more help on this it would be great to see the complete entities User and Customer.
It is happening because in your database the parameter will be a #oneToOne object and you have to call the id inside the Object so you have to give the query as following :
"select user from User user where user.customer.id=:param"

Entity framework code first and data annotaions

I use code first approach in my project. In the prject I have classes with MetadataType attribute, which I don't use in my EF model. Class with metadata has some constant public fields (in addition to fields from main type). Now when I tried to query EF it threw exception that in metadata class there fields not mapped... se below in details
class M1
{
int Id;
string Name
}
class M2
{
int Id;
DateTime Date
}
[MetadataType(typeof(PageOFSRevenueMetadata))]
class NotRelatedToModel
{
int Prop1;
int Prop2;
}
class PageOFSRevenueMetadata
{
public const string RuleSet1 = "r1";
public const string RuleSet2 = "r2";
// Data Vaidation Attrs...
int Prop1;
int Prop2;
}
In my context I have mapping only for M1 and M2. In the DB exists table with name 'NotRelatedToModel', but I don't want to use it in my model. I use EF 6
Now when I try to make join query on M1 and M2 it threw below exception
'NotRelatedToModel' contains the following unknown properties or fields: RuleSet1, RuleSet2. Please make sure that the names of these members match the names of the properties on the main type
I can move this static fields to another place and it seems to work, but I would like to know why it is happend ? How the EF code first mapping works ?
Thanks in advance