Mark complete entity as "updatable=false" - jpa

In one application there are several entity classes, for which update statements to the database shall be forbidden. I want to insert into and read from the database, but never do any updates on existing records.
Is there a way to mark a whole #Entity class as updatable=false?
One could annotate every single field with #Column(updatable=false) or similar annotations, but for obvious reasons I'd like to avoid this.
Getting rid of the setter methods is not an option as well, because the entity classes are also used as DTOs and other parts of the application need those setters. so this would cause to much refactoring of existing code.
Is there another simple and clean way to achieve what I'd like to have with JPA 2.1 / EclipseLink (+Extensions)

You could use #PreUpdate for that:
#Entity
public class ReadOnlyEntity {
#PreUpdate
private void preUpdate() {
throw new UnsupportedOperationException();
}
}
That way you can never update (write) that entity.

Related

Why JPA entities are treated like this outside a session?

Hy,
I am having a "Solve failed to lazily initialize a collection of role.... exception" in jpa. I understand that outside a session, when you want to retrieve a lazy collection if there is not session bound you will get this error, fine. But what I dont understand is if I have this spring controller(the code is not 100% correct, is just to explain my case):
#Controller
#Autowired
EnterpriseService enterpriseService ;
public List<Enterprise> getAll(){
List<Enterprise> enterprises = enterpriseService.getAll();
for(Enterprise enterprise:enterprises){
enterprise.getEmployees();
}
return enterprises;
}
When I call "enterprise.getEmployees()", I know there is not anymore a session but why when I try to do "enterprise.getEmployees()", why enterprise is treated like a jpa entity and not just like a normal bean?, I mean; for what I understand a jpa entity is treated like this inside a session but outside like in this case it should be treated like a normal java bean so the calling to enterprise.getEmployees() should be treated like the calling of a get method of a java bean and should not throw any lazy exception....
Maybe is because spring controller treats the enterprise objects like jpa entities and not just only like java beans? this behaviour is specific to spring controllers?
Thanks
An entity returned from an EntityManager is not necessarily an instance of your entity class, but a proxy class which extends your class. In many cases the same is true for the persistent properties of such entities (especially for those annotated with (One/Many)To(One/Many)).
For example if you are using field based access:
#Entity
public class Enterprise {
#OneToMany
private List<Employee> employees = new ArrayList<>();
public List<Employee> getEmployees() {
return employees;
}
}
Here the JPA provider will create a proxy class that extends Enterprise and remembers the previous state from the DB somehow. In addition it will change the employees list to its own implementation of List (which does not need to extend ArrayList).
Because the proxy class can "overwrite" your methods, it could know when you are calling getEmployees() and check for the session. But I don't think that this would happen here, as the method is not annotated with any JPA specific annotation.
In addition some frameworks like Hibernate do support byte code enhancement or byte code instrumentation. That changes the implementation of your class (in byte code) and replaces every access to employees with some provider specific code. I don't know if Spring JPA provides this, but this could lead to check for a session.
Otherwise any call to enterprise.getEmployees() should just return the current value of employees - without any check for the session and without the LazyInitializationException.
But calling enterprise.getEmployees().size() will try to initialize the list and check for the session - this could lead to the mentioned exception.
If you are using property based access things are a little bit different:
#Entity
public class Enterprise {
private List<Employee> employees = new ArrayList<>();
#OneToMany
public List<Employee> getEmployees() {
return employees;
}
}
Here the proxy class will not delegate to your implementation, but overwrite the getEmployees() method and return its own List implementation, without changing employees. Thus here it is possible to get a LazyInitalizationException for enterprise.getEmployees().
Remark: This describes how most JPA implementations are working - but as this is implementation specific some unusual frameworks could do things differently.
It can't do anything else. The only alternative would be to return an empty collection of employees, which would be much much worse: you would incorrectly assume that the enterprise has 0 employee, which is a valid, but completely incorrect result.
To realize how much worse it would be to do that, let's imagine a HospitalAnalysis entity, having a collection of DetectedDisease entities. And let's say you try to display the result of the analysis but forget to initialize the collection. The page would tell you that you're perfectly healthy and that you can safely go home, whereas in reality, you have a cancer, and the program has a bug. I'd much prefer the program to crash with an exception and be fixed rather than not starting my treatment.
Trying to access employees without having initialized the collection, and thus without knowing the actual collection of employees, is just a bug. This bug is signalled by throwing a runtime exception.

Resuable Coding with Unit Of Work Pattern in Entity Framework

Lets assume that below code retrieves data from database via Unit Of Work pattern.
Since the GetByID is the common operation, it can be declared inside Repository class.
UnitOfWork w = new UnitOfWork();
w.someRepository.GetByID(10);
What if i need to call GetByID method in 10 seperate files. Should i create an instance of UnitOfWork class and call GetByID in every time or does the code-block below is valid for UnitOfWork pattern?
public class SomeRepositoryProvider {
public tbl_somerepoclass GetByID(int id) {
UnitOfWork w = new UnitOfWork();
return w.someRepository.GetByID(10);
}
}
Generally you shouldn't even need UnitOfWork when you want only to retrieve data from database. UnitOfWork is more like transaction to db - you try to persist some set of data to db in one go - if everyfing goes ok it is saved, if not then everything is rollback. To get entities by ids you should only need Repositories. The best solution I encountered in my practice is to for each entity prepare Repository class and prepre there useful methods. Only if you want to save the data use UnitOfWork. So generally you should use your repostiory like that:
someRepository.GetById(10);
When you instantiate Repository just pass to its constructor proper object needed for the operations - in case of entity framework ver. > 4.0 DbContext.
If you want to add new entity use it like that:
someRepository.Add(newEntity);
unitOfWork.Save();

When using JPA entityManager why do you have to merge before you remove?

For a while now I have been wondering why when using JPA, do I have to write my delete methods like this:
#Transactional
public void delete(Account account)
{
if (entityManager.contains(account))
{
entityManager.remove(account);
}
else
{
entityManager.remove(entityManager.merge(account));
}
}
Perhaps the contains isn't needed since the transaction begins and ends with this method, but I still wonder why the remove couldn't just take an unmanaged object. Is it because it needs to be managed in order to know what the id is for that object? Any other insights would be great to hear. I just want to understand the hows and whys of the JPA remove.
The remove operation can be cascaded to associations of an entity.
To be able to know which associated entities to remove, the entity manager can't rely on a detached entity, since, by definition, this detached entity doesn't reflect the latest state of the entity, and doesn't necessarily have all its cascaded associations recursively loaded.
So, if it accepted a detached entity, remove() would have to decide for you: either merge the detached entity and execute the remove operation based on what the detached entity contains, or simply load the entity having the same ID as the detached entity, and execute the operation based on the loaded entity.
Instead of deciding for you, it simply requires an attached entity. That way, you decide what you want.

POCO Entity Framework 4 With IRepository Pattern Collection Was Modified Error on Delete

We have a IRepository pattern working quite well for us with our EF and POCO first setup. However we are getting a strange problem with a "Collection was modified; enumeration operation may not execute".
Basically we have a repository with an ObjectSet as follows:
protected IObjectSet<T> ObjectSet
{
get
{
if (_objectSet == null)
{
_objectSet = this.Context.CreateObjectSet<T>();
}
return _objectSet;
}
}
And a delete method on the IRepository class which is implemented as follows:
public void Delete(T entity)
{
ObjectSet.DeleteObject(entity);
}
It's all very straightforward and we've had no problems up until this point but whenever we try to delete an object of a collection we get this error. If I put a breakpoint on the delete method hover over ObjectSet and expand the results so it's all loaded then the DeleteObject works fine but if all the items are not loaded form the ObjectSet it fails with the collection modified error.
I set up a testbed not using POCO or IRepository and it works fine so basically is there something really obbvious that I am missing. We are quite deep into using this pattern in multiple projects and people have been working around it rather than trying to fix it which isn't an option I don't think.
Many thanks for any help or insight.
EDIT:
This is very strange but when I remove certain entities from the model this error goes away but we have a huge model and I can't track it down as I first removed everything but the specific tables in the delete. Has anyone ever come across this before, we are using inheritance tables (per type) but I can't prove this is the problem.
SECOND EDIT:
OK I removed everything from the model except the table per type inheritance entites and the error occurs, when I remove all but one derived type and try to delete from that it works fine. So my question is has anyone else had this problem when using the table per type inheritance?
It's a bug in Entity Framework. Fixed in 4.5 according to connect.

Repository pattern with EF4 CTP5

I'm trying to implement the repository pattern with ef4 ctp5, I came up with something but I'm no expert in ef so I want to know if what I did is good.
this is my db context
public class Db : DbContext
{
public DbSet<User> Users { get; set; }
public DbSet<Role> Roles { get; set; }
}
and the repository: (simplified)
public class Repo<T> : IRepo<T> where T : Entity, new()
{
private readonly DbContext context;
public Repo()
{
context = new Db();
}
public IEnumerable<T> GetAll()
{
return context.Set<T>().AsEnumerable();
}
public long Insert(T o)
{
context.Set<T>().Add(o);
context.SaveChanges();
return o.Id;
}
}
You need to step back and think about what the repository should be doing. A repository is used for retrieving records, adding records, and updating records. The repository you created barely handles the first case, handles the second case but not efficiently, and doesn't at all handle the 3rd case.
Most generic repositories have an interface along the lines of
public interface IRepository<T> where T : class
{
IQueryable<T> Get();
void Add(T item);
void Delete(T item);
void CommitChanges();
}
For retrieving records, you can't just call the whole set with AsEnumerable() because that will load every database record for that table into memory. If you only want Users with the username of username1, you don't need to download every user for the database as that will be a very large database performance hit, and a large client performance hit for no benefit at all.
Instead, as you will see from the interface I posted above, you want to return an IQueryable<T> object. IQuerables allow whatever class that calls the repository to use Linq and add filters to the database query, and once the IQueryable is run, it's completely run on the database, only retrieving the records you want. The database is much better at sorting and filtering data then your systems, so it's best to do as much on the DB as you can.
Now in regards to inserting data, you have the right idea but you don't want to call SaveChanges() immediately. The reason is that it's best to call Savechanges() after all your db operations have been queued. For example, If you want to create a user and his profile in one action, you can't via your method, because each Insert call will cause the data to be inserted into the database then.
Instead what you want is to separate out the Savechanges() call into the CommitChanges method I have above.
This is also needed to handle updating data in your database. In order to change an Entity's data, Entity Framework keeps track of all records it has received and watches them to see if any changes have been made. However, you still have to tell the Entity Framework to send all changed data up to the database. This happenes with the context.SaveChanges() call. Therefore, you need this to be a separate call so you are able to actually update edited data, which your current implementation does not handle.
Edit:
Your comment made me realize another issue that I see. One downfall is that you are creating a data context inside of the repository, and this isn't good. You really should have all (or most) of your created repositories sharing the same instance of your data context.
Entity Framework keeps track of what context an entity is tracked in, and will exception if you attempt to update an entity in one context with another. This can occur in your situation when you start editing entities related to one another. It also means that your SaveChanges() call is not transactional, and each entity is updated/added/deleted in it's own transaction, which can get messy.
My solution to this in my Repositories, is that the DbContext is passed into the repository in the constructor.
I may get voted down for this, but DbContext already is a repository. When you expose your domain models as collection properties of your concrete DbContext, then EF CTP5 creates a repository for you. It presents a collection like interface for access to domain models whilst allowing you to pass queries (as linq, or spec objects) for filtering of results.
If you need an interface, CTP5 doesn't provide one for you. I've wrapped my own around the DBContext and simply exposed the publicly available members from the object. It's an adapter for testability and DI.
I'll comment for clarification if what I said isn't apparently obvious.