Win a copy of TensorFlow 2.0 in Action this week in the Artificial Intelligence and Machine Learning forum!

Rob Spoor

Sheriff
+ Follow
since Oct 27, 2005
Rob likes ...
Eclipse IDE Spring VI Editor Chrome Java Ubuntu Windows
Cows and Likes
Cows
Total received
108
In last 30 days
1
Total given
50
Likes
Total received
1618
Received in last 30 days
4
Total given
2386
Given in last 30 days
20
Forums and Threads

Recent posts by Rob Spoor

Campbell Ritchie wrote:

. . . .getString("A").equals(-3.82)). . . .

That use of equals() looks dubious to me; maybe you have missed out some quote marks.


Campbell's right. That expression always returns false, because a String never equals a Double. Your list will be empty.
1 hour ago

Glenda Karen wrote:


You can make that slightly shorter by moving the boxing into the mapping, where the double is auto-boxed.
1 hour ago
Or switch to Apache HttpClient. I've been using that one for years, lately even with version 5, since that supports HTTP/2.
1 hour ago
At least they were faster with the bug I found earlier this year: java.util.Properties.entrySet() does not override java.lang.Object methods. Although it's been in the JDK from Java 9 until 15 (fixed in 16), it was fixed within 2 months after it was reported.
1 hour ago

Deyan Perov wrote:

There will never be a third table when using @OneToMany / @ManyToOne / @OneToOne unless you explicitly tell JPA to use one. A unidirectional @OneToMany will still use a join column in the MANY table; the MANY entity just doesn't use it itself. With @JoinColumn you tell JPA explicitly what the column looks like instead of having JPA using its defaults.



I mean by this: https://vladmihalcea.com/the-best-way-to-map-a-onetomany-association-with-jpa-and-hibernate/ Unidirectional @OneToMany


I guess I was wrong - JPA by default does use a third table, and you have to tell it explicitly to not do this. I'm a bit surprised that Hibernate isn't smart enough to merge the INSERT and UPDATE into one though. I wonder how that will behave if you use @JoinColumn(nullable = false). Perhaps that will tell JPA that it needs to set the column during INSERT.

There's an alternative to unidirectional @OneToMany: @ElementCollection. In this case, the MANY side isn't an entity of its own, it's completely owned by the ONE side. There is a drawback of course - because the MANY side isn't an entity, it doesn't have a primary key as far as JPA is concerned (it can and should of course have one in the database). That means that updating such records may not work as you expect it to be - it could be implemented as DELETE + INSERT for each record on the MANY side.

As you can see I am not conformable with JPA, Hibernate, and Relationships. Could you please suggest to me some good documentation where I can read about it? I am going to search over coderanch too, maybe I will find some interesting text which can help me not to be confused.


It's not free, but I recommend Pro JPA 2. This is one of the books I've read in preparation for my JPA exam.
Welcome to the Ranch!

You'll have more success in our Server-Side JavaScript and NodeJS forum, so I moved this thread to there.

What is your problem? If you tell us, people will be able to help you immediately.

Deyan Perov wrote:Rob Spoor, I want to thank you for all your effort to help! But now when I scratched deeper I am still confused and now I have many more questions...

On a JPA level, the one without mappedBy is the owner. By default with @ManyToOne / @OneToMany, that means the MANY side.



I always think the owner is ONE because I thought MANY of something depends on that ONE.


Maybe from a logical or DB perspective, but from a JPA perspective, the MANY is the owner side of the relationship. Probably because it has the foreign key. If you add a MANY entity to the ONE without setting the ONE on the MANY, the foreign key will not be set. You should also use the same principle for MANY to MANY - always add to the owning side. Adding to the other side is optional for JPA, but good practice for your in-memory model.

Note that if you forget the mappedBy with @ManyToMany, you get two unidirectional relationships. If you add the entities to each other, that will lead to two INSERT statements. If they use the same @JoinTable that will trigger a unique constraint violation (assuming you've added the correct constraints / pkeys). I've seen this happen myself.

It's possible to change the owner to Town, but that means that you should remove the (explicit) relationship from the Student side, basically creating a unidirectional relationship.  


I this case it will be created a new table and I will have 3 tables instead of 2. This can be prevent with @JoinColumn?


There will never be a third table when using @OneToMany / @ManyToOne / @OneToOne unless you explicitly tell JPA to use one. A unidirectional @OneToMany will still use a join column in the MANY table; the MANY entity just doesn't use it itself. With @JoinColumn you tell JPA explicitly what the column looks like instead of having JPA using its defaults.

@ManyToOne on Student. Town doesn't even need @OneToMany to get the foreign key; it's a unidirectional many-to-one without it.
@OneToMany without mappedBy on Town, and no @ManyToOne on Student. This is a unidirectional one-to-many.
@OneToOne with mappedBy on Student. Note that the non-owner side needs mappedBy with @OneToOne.



This is new to me... First I have to understand bidirectional and unidirectional. Bidirectional doesn't exist in relational databases, there exist only undirectional, right? Table A has a FK from Table B, but Table B doesn't have a FK from Table A, right? And this is undirectional?
We need to bidirectional on the level of Java because we need to have a reference for an object in a class. i.g. We have a Student which HAS-A Town, Town HAS-A student. Am I right? The student has to know for the Town, and the Town has to know for the Student.



But if the Town doesn't have a reference of the Student is that undirectional then?


Right on both accounts. Relational DBs indeed only know unidirectional. The MANY refers to the ONE.
In JPA, a relationship is unidirectional if one of the sides has as reference to the other, but not the other way around. A relationship is bidirectional if both entities have references to each other. The latter is often preferred but it's allowed to create unidirectional relationships if you only need to traverse the relationship one way. That could be from MANY to ONE, but also from ONE to MANY. It all depends on your needs. I often see bidirectional relationships out of habit though.

Paul Clapham wrote:I gave you a cow for such a comprehensive answer, Rob. I also gave Deyan a cow for posting such a well-formed comprehensively-answerable question.


Thanks

Dave Tolls wrote:

Deyan Perov wrote:
I have Town which can have many Students. Student(s) can exist without Town and Town can exist without Student(s).



Rob's covered everything, but I didn't notice whether he spotted this.

You say a Student doesn't have to have a Town...OK, but your StudentEntity has its TownEntity marked as NotNull.


I missed that, but you're completely right.

Deyan Perov wrote:A town is the OWNER of a relationship.


Perhaps on a database level. On a JPA level, the one without mappedBy is the owner. By default with @ManyToOne / @OneToMany, that means the MANY side. It's possible to change the owner to Town, but that means that you should remove the (explicit) relationship from the Student side, basically creating a unidirectional relationship. That's a bit more advanced though, so let's skip that step.

One warning: don't just remove mappedBy. If you have both a @ManyToOne and a matching @OneToMany but the latter one does have a mappedBy, then you don't have one relationship. You have two relationships that involve the same entities. It's very error prone, so please don't do it. (The same holds for two @ManyToMany or two @OneToOne; one side always needs mappedBy.)

To tell Hibernate who is the owner we use @OneToMany(mappedBy = "townEntity").


Yes, but by specifying mappedBy you specify that the other side is the owner.

And this means in the Student table it will be created foreign key town_id, right?


Right. This will be done for any relationship in which Student needs a link to Town:
  • @ManyToOne on Student. Town doesn't even need @OneToMany to get the foreign key; it's a unidirectional many-to-one without it.
  • @OneToMany without mappedBy on Town, and no @ManyToOne on Student. This is a unidirectional one-to-many.
  • @OneToOne with mappedBy on Student. Note that the non-owner side needs mappedBy with @OneToOne.


  • @JoinColumn(name = "town_id") - I just don't see the difference when I have this and don't understand when to use it because I saw codes without it too. I read it about it but...Probably I missed something more from relationships to understand when I have to use it. I am not sure when I need it and what exactly does it when I "get" the same with mappedBy.


    By default, the JPA provider tries to guess the column name. It does this by taking the entity name and appending _id. By using @JoinColumn you can make it explicit, or override the default.

    Before I ask about JSON annotations let me say about the other problem.
    This works, when I POST Student it creates the Student and his Town. When I create another Student with the same Town name it has the id from that Town (id = 1) but when I change some attribute in Student and want to PUT it I get some changes. A new Town is created with the same name and has id = 2, the Student which I updated now has foreign key town_id = 2. Why?

    I want to have to Create, Read, and Update a Town. I don't need it deletes. But when I change a Student and if I don't touch a Town information I want to stay the same.


    Any entity without an id will be considered new, and will trigger an insert. If you update a Student, that Student has an id. If its Town does not, the cascade will cause a new one to be created. That's because CascadeType.ALL implies PERSIST. In order to update the Town as well, it needs to have an id before saving the Student.

    One interesting thing about your Town. It looks more like an Address. I understand that multiple Students can live at the same Address. But how would you support moving a Student to a different Address? If you update the existing one, all other Students at the same Address will belong to the same updated Address. It would appear that all of the Students moved instead of just the one. This is something to think about carefully.

    To avoid infinite JSON loop I use and . But when I want to GET a Student it doesn't show my any data of his Town. I found this can help me but I am not sure is that what I need it

    Because when I GET a Student Postman backs me the Student with his Town and the Town has an array of all Students who have FK of that Town.


    I hate directly exposing entities, because you have to work hard often to prevent these loops. It will give you more problems than you want. Instead, I prefer to create a DTO class for the REST interface. These don't have the bidirectional relationship, just the one you want. For creating you'd have to convert the DTO into an entity and save it; for updating you'd need to find the existing entity, update it from the DTO, and save it.

    Gerard Gauthier wrote:

    Rob Spoor wrote:... Just remember that any project using the dependency cannot be built by others that don't have the dependency.



    So basically(since the dependency is local) I can only build I it on my machine. Right?


    Right.

    I kind of figured out how dependencies work by exploring my ~/.m2 folder and the pom.xml's dependency section.



    I just walked into my ./m2 folder using the tags for junit as steps.


    It's probably a good idea to read Introduction to the Dependency Mechanism at least once. It tells you some more about scopes etc.

    I'd like to point you to https://search.maven.org/ and https://mvnrepository.com/. They both let you do the same thing (find available dependencies and their versions), which one to use is purely personal preference. I prefer the second, even though the first one is more "official".
    1 week ago
    Anything that's available in your local repository can be added as a dependency in your Maven project, as if it were available for everyone. Just remember that any project using the dependency cannot be built by others that don't have the dependency.
    1 week ago

    Tim Holloway wrote:For proper I18N processing of general text from a file, I'd recommend that you open a FileInputStream, then construct an InputStreamReader on that. Or on System.in, if using stdin. The InputStreamReader allows you to set the proper charset for your input so that stuff like accented letters get handled properly and cleanly. Note that FileReader doesn't appear to have any characterset constructors itself.


    FileReader got two constructors that take a Charset in Java 11. I've been using the FileInputStream-in-InputStreamReader workaround for ages, so I was quite glad to see these constructors finally being there.

    Once you have a properly-configured Reader, I recommend using it to construct an LineNumberInputReader. This gives you (non-deprecated) readLine() methods plus if you need to complain about input, you'll have the offending line number already available without having to implement line-counting logic of your own.


    I think you mean LineNumberReader. I can't remember ever using that though, BufferedReader usually works good enough for me.
    1 week ago
    The three annotations have different purposes.

    @QueryParam (javax.ws.rs) only works with JAX-RS. In other words, the web layer. It's meant to map a query parameter to a method argument. It cannot be used with Spring's @Query annotation.

    @Param(org.springframework.data.repository.query.Param) is meant to be used in combination with @Query to define that a method argument should be mapped to a parameter inside the query. This is the one you need.

    @Parameter(org.hibernate.annotation) is some Hibernate specific thing. No idea how it works, but it cannot be used with Spring's @Query annotation.
    2 weeks ago