I'm using EJB 3.1 and JPA 2.0.
I'll give you an example to explain my doubts and ask for hints as what is a good practice and what's not.
Let's say I have an EJB that's a user Facade. So you have something like this:
#Stateless
public class UserRepository {
public User find(Long id) {
...do user lookup using entitymanager.
}
}
Alright, now let's say I return the User entity from this and that this entity has a collection of comments (Comment being also an entity).
I could have a Comment Repository with a findCommentsByUser(Long userId) method, or I could fetch the user and call the getComments() method. May be this case is simple, but I've faced this decision many times sometimes not knowing what is best.
Also, let's say I want to add a comment, should I add it to the comment collection the entity has and the have the entity merged, or should I have a addComment(Long userId, Comment newComment) method?
I'm looking for advice or best practices regarding this. If you need further clarifications please do not hesitate to ask.
EDIT:
I've found the comments so far helpful, however notice this, it isn't really about users and comments, I just made that up to explain my situation. It's about whether it is convenient to mix both approaches (which I think is not) or is one better over the other. I liked the "always persist through the repositories" suggestion. But the fact that I have a fetchComments() repository method and the getComments() in the user entity creates to entry points for the same functionality, so how do I deal with that?.
Also the performance (1 query vs 2 queries) isn't really important because I will be fetching the user entity too so it's not like I'm actually saving anything.
We typically only work with detached entities in our applications, so we have a data access manager to fetch and update entities. Then we know that anything we do in our business logic will not be persisted unless specifically called to. I would also fetch the comments with the user entity, but make sure it is not persisted until explicitly called.
I could have a Comment Repository with a findCommentsByUser(Long
userId) method, or I could fetch the user and call the getComments()
I would say that from a performance point of view, the first alternative is slightly better, because you don't fech the user (1 query) and then the comments (another query). The first does it in a single shot.
In the other side, i find the second more readable, abstract, and object oriented approach. I would use this one.
You would generally add the getComments() method to your user object. When you want to add one, you would add it to the user set and then call update on the user object.
I think this highly depends on the requirements, on how fine-grained control of the process do you want to have (this often depends on the performance requirements and expected load, etc.).
If the comments are never to be retrieved independently, I would only keep them as a reference inside User.
If you, however, want to get the comments regardless of the user, or you want to perform some other comments-related queries (like all the comments for users in group A), then I would create separate CommentsRepository.
If you want to be able to add the comment to a user that's not loaded from the DB, but you have the foreign key, you may simply want to add the comment through CommentsRepository like you suggested (also adding a comment to a list of user's comments in parallel and persisting such two lists into DBs may result in 'weird behavior').
There are several considerations that needs to make I hope I will document them here for you.
Domain model is important consideration in EJB3. In your example if you see your domain model allows you to fetch comments lazily because in any flow you show user details first and then his comments.
In some cases your collection (I am referring to comments here) may contain lots of data, In this case its hardly question of string data so not a major concern, but if it would have been real application data then always opt for transient relationship and provide appropriate methods to fetch them independently.
Its never a good practice to expose your collection inside entity bean to outside world so if you OneToMany or ManyToMany relationship then you should provide three basic methods over collections (add, remove, get).
Collections.unmodifiableCollection method should be used while returning collections from get method.
Always use Set when you are using collections inside entities remember they do not allow duplicate.
In your case comments collection has direct dependency on user so you should use cascade type in user to save comments.
I am not convinced why you need UserRepository because em.find method will do job for you.
By default for OneToMany relation fetchtype is lazy so if you want to do eager load you will need to specify it.
I hope these guidelines hopes to solve your problem.
Regards,
Amit
Related
In our code base we make extensive use of DAOs. In essence a layer that exposes a low level read/write api and where each DAO maps to a table in the database.
My question is should the dao's update methods take entity id's or entity references as arguments if we have different kinds of updates on an entity.
For example, say we have customers and adressess. We could have
customer.address = newAddress;
customerDao.updateCustomerAddress(customer);
or we could have
customerDao.updateCustomerAddress(customer.getId(), newAddress);
Which approach would you say is better?
The latter is more convenient since if we have the entity we always have the id, so it will always work. The converse is not always the case though, but would have to be preceded with getting the entity before performing the update.
In DDD we have Aggregates and Repositories. Aggregates ensure that the business invariants hold and Repositories handle the persistence.
I recommend that Aggregates should be pure, with no dependencies to any infrastructure code; that is, Aggregates should not know anything about persistence.
Also, you should use the Ubiquitous language in your domain code. That being said, your code should look like this (in the application layer):
customer = customerRepository.loadById(customerId);
customer.changeAddress(address);
customerRepository.save(customer);
I assume your question is
Which approach of the two is better?
I would prefer the second approach. It states clearly what will be done. The update object will be freshly loaded and it is absolutely clear that only the address will be updated. The first approach leaves room for doubt. What happens if customer.name has a new value aswell? Will it also be update?
I can't seem to find the correct wording to search the web and get the right answer. So, every time I have an object that has a collection of other objects I get stuck on figuring out how to design the relationships.
For instance, a very rudimentary example would be..
So, I have a Person who can have many addresses. I know it would be incorrect to have the PersonDAO also create Addresses and put them in the Person object so how would I go about having one method (listAll()) for Person objects but have them come back with all of their addresses as well?
I hope this makes sense, please let me know if I need to clarify.
Also, the only thing I could find online that looked somewhat accurate was to use a CollectionsDAO but I wasn't sure how that would work so I threw it in there in red.
One solution would be to have the PersonDAO call the AddressDAO to get the Addresses and put them in the Person object(s) it returns. This would go inside a separate listFull() method or something of the sort. If an "Address" is a part of a "Person", I don't know that it is conceptually wrong for the PersonDAO object to also know how to populate Person instance with Address records. And making PersonDAO call AddressDAO to do the actual data access would seem to provide good separation of concerns (each DAO accesses it's own table and delegates to other DAOs where it needs to get more data to return more complex results).
As #Thieson alludes to, you have to ask yourself why you are bothering to derive. If there is functionality that you really do want to inherit and reuse between them, then fine. But otherwise there may be no point. I've seen a number of systems with a large quantity of objects where there is no direct hierarchy between the various DAO objects (broadleaf for example).
You'll probably get several answers here telling you to simply do whatever makes the most sense, and that's definitely good advice.
You don't have to necessarily follow your entity relationship schema on your DAOs.
You can simply add a method called listAllWithAddress, for example, in the PersonDAO or create a separated DAO called PersonAddressDAO to represent their relationship.
There are no rules regarding that, but your own sense of judgement.
Regardless your comment about not adding the method, i would add the method in the PersonDAO, because it is going to return to me Person entities anyway, even if the addresses are populated.
My advice to you is to worry more about making sense then following restrictive rules
So the question is pretty much in the title.
Let's say I have some classe: User, Post, Comment and Tag.
User has a #OneToMany List and
#OneToMany List.
Post has
#ManyToOne User, #OneToMany
List, #ManyToMany List.
Comment has #ManyToOne List,
#ManyToOne User.
Tag has #ManyToMany
List.
I'm new to Hibernate, but I find it easy then to use for example the attributes of a Tag object to get all the Post objects related to that tag, or find the author of a Post object or all the Post written by a certain User.
Is it OK ?
I'm talking more in terms of performance here. I'm also using the Play! framework. I don't know if this changes anything.
I think some of them should be unidirectional.
For example, in real-world scenario you usually don't need to display "all Posts by User", because they should be filtered or paginatied, so you need to run queries against the database instead of retrieving Posts from the User (because not filtering a collection at the database side in these use cases can be a real performance problem, especially if that collection is huge).
Therefore having collection of Posts in User makes no sense. The same is true for User - Comment and Tag - Post relationships.
It is ok to have bidirectional relationships. The real danger is in also having lazy false, because then you will end up loading a lot of your db into memory for every request.
If you have bidirectional relationships, it is good practice to create specific dao methods that allow you to load only the data you need, with hql.
In my hypothetical I have an annotated User model class. This User model also holds references to two sets:
A set of Pet objects (a Pet object is also an annotated model represented in the data layer)
A set of Food objects (a Pet object is also an annotated model represented in the data layer)
When I pull the User entity from the database (entityManager.find(User.class, id)) it will automatically fill all the User fields but it obviously wont fill the two sets.
Do I need to do entityManager.createQuery and just use a normal SQL join query then manually create the User object?
Thanks in advance
If you map your relations from User to Pet and Food using OneToMany you can chose whether to have the fields automatically collected or not.
See the API doc for javax.persistence OneToMany.
Depending on how you constructed the mapping (PK-FK or join tables etc), you may or may not get good performance with this. Having two OneToMany relations that are joined, means you may end up with a ridiculous amount of rows when you read up your user.
Mmm, No? That's probably not how you want to do it. I don't know why you say "it obviously won't fill the two sets." It's quite capable of filling in the sets for you, that's sort of the point behind using an ORM like hibernate in the first place. Your objects do what they look like they should in code and 'databasey' things are handled automatically as much as possible.
It is true that Hibernate will complain if you mark more than one collection as EAGER fetched, but it's not really clear you actually need either of them to be eager. Essentially once they are mapped, just accessing them causes the queries to be run to fill them in with data (assuming the Session is still open and so forth.) If you explain how you want it to work it would be easier to help with a solution.
I have the following use case: There's a class called Template and with that class I can create instances of the ActualObject class (ActualObject copies its inital data from the Template). The Template class has a list of Product:s.
Now here comes the tricky part, the user should be able to delete Products from the database but these deletions may not affect the content of a Template. In other words, even if a Product is deleted, the Template should still have access to it. This could be solved by adding a flag "deleted" to the Product. If a Product is deleted, then it may not be searched explicitly from the database, but it can be fetched implicitly (for example via the reference in the Template class).
The idea behind this is that when an ActualObject is created from a template, the user is notified in the user interface that "The Template X had a Product Z with the parameters A, B and C, but this product has been deleted and cannot be added as such in ActualObject Z".
My problem is how I should mark these deleted objects as deleted. Before someone suggests that just update the delete flag instead of doing an actual delete query, my problem is not that simple. The delete flag and its behaviour should exist in all POJOs, not just in Product. This means I'll be getting cascade problems. For example, if I delete a Template, then the Products should also be deleted and each Product has a reference to a Price-object which also should be deleted and each Price may have a reference to a VAT-object and so forth. All these cascaded objects should be marked as deleted.
My question is how can I accomplish this in a sensible manner. Going through every object (which are being deleted) checking each field for references which should be deleted, going through their references etc is quite laborious and bugs are easy to slip in.
I'm using Hibernate, I was wondering if Hibernate would have any such inbuilt features. Another idea that I came to think of was to use hibernate interceptors to modify an actual SQL delete query to an update query (I'm not even 100% sure this is possible). My only concern is that does Hibernate rely on cascades in foreign keys, in other words, the cascaded deletes are done by the database and not by hibernate.
My problem is how I should mark these
deleted objects as deleted.
I think you have choosen a very complex way to solve the task. It would be more easy to introduce ProductTemplate. Place into this object all required properties you need. And also you need here a reference to a Product instance. Than instead of marking Product you can just delete it (and delete all other entities, such as prices). And, of course, you should clean reference in ProductTemplate. When you are creating an instance of ActualObject you will be able to notify the user with appropriate message.
I think you're trying to make things much more complicated than they should be... anyway, what you're trying to do is handling Hibernate events, take a look at Chapter 12 of Hibernate Reference, you can choose to use interceptors or the event system.
In any case... well good luck :)
public interface Deletable {
public void delete();
}
Have all your deletable objects implement this interface. In their implementations, update the deleted flag and have them call their children's delete() method also - which implies that the children must be Deletable too.
Of course, upon implementation you'll have to manually figure which children are Deletable. But this should be straightforward, at least.
If I understand what you are asking for, you add an #OneToMany relationship between the template and the product, and select your cascade rules, you will be able to delete all associated products for a given template. In your product class, you can add the "deleted" flag as you suggested. This deleted flag would be leveraged by your service/dao layer e.g. you could leverage a getProdcuts(boolean includeDeleted) type concept to determine if you should include the "deleted" records for return. In this fashion you can control what end users see, but still expose full functionality to internal business users.
The flag to delete should be a part of the Template Class itself. That way all the Objects that you create have a way to be flagged as alive or deleted. The marking of the Object to be deleted, should go higher up to the base class.