I have two stored procedure calls that return a User entity. One looks to see if the user is registered by two parameters not included in the user entity. If the procedure does not return any users, a second stored procedure is called to register that user.
The behavior I'm seeing is that when called in this order, the second stored procedure returns a User entity from the cache that has nearly all the fields as null. When I disable caching it returns the user object appropriately. It would seem that the first call is caching the user object.
In normal operation where a user is logging in, I want it to cache, so I do not want to disable caching for the first call. I want the second stored procedure call to not use the cache. After doing some research and testing a few options, I've found few options.
This doesn't work on a stored procedure:
proc.setHint("javax.persistence.cache.retrieveMode", CacheRetrieveMode.BYPASS);
java.lang.IllegalArgumentException: Query linkUser, query hint javax.persistence.cache.retrieveMode is not valid for this type of query.
This looks like evicts all the cache for all Users.
em.getEntityManagerFactory().getCache().evict(User.class);
And these options either disable cache for all instances of the entity or across the application.
How can I not use cache for a single stored procedure call with Eclipselink?
Bonus: Why would a stored procedure call that returns a null user be cached?
The JPA specification requires that all entities returned from JPA queries (which includes native and Stored proc queries) be managed, which implies they are also cached to maintain object identity. If your first query is returning an incomplete entity, this too will be cached. Applications need to be careful when using queries that return entities that they return a complete set of data or they can corrupt the cache, and also note that their entities may be pulled from the cache instead of rebuilt with the data from their query, and may want to return java objects (constructor queries) rather than JPA entities.
For the answer to the first part, see https://stackoverflow.com/a/4471109/496099
Found a Java EE Tutorial that shows how evict an individual cache. I'm still not sure why it's even being cached because the first call never has the userId.
Cache cache = em.getEntityManagerFactory().getCache();
cache.evict(User.class, userId);
Related
We have an entity and a corresponding table in the database with one additional column which contains digested hash of the entity fields, calculated each time programmatically in application. Entity has associations with two additional tables/entities which fields also take part in hashing.
Now a decision was made to get rid of one of the fields from the main entity (boolean flag) and exclude it from hashing, since it makes two otherwise identical entities get different hashes when one entity has its flag set to true, while other is false. Since hashes are different both entities get stored in the database, which is not what we want.
Removing the field is simple, but we also need to re-calculate hashes for entities which have been already stored in the database. Since there might be duplicates, we also need to get rid of one of two duplicated entries. This whole operation must be done once after migration.
The stack we use is Quarkus, Flyway, Hibernate with Panache, and PostgreSQL. I have tried to use Flyway callbacks with Event.AFTER_MIGRATE to get all existing entities from the db, but I can't use Panache since its not initialised yet by the time callback hits. Using plain java.sql.* Connection and Statement is pretty cumbersome, cause I need to fetch data from 3 tables, create entity from all of the fields, re-calculate hash and put it back, while taking care of possible conflicts. Another option would be to create a new REST API endpoint specifically for the job which the client will have to call after app has booted, but somehow I don't feel that that is the best solution.
How do you tackle this kind of a situation?
working with Spring data JPA and reading it Hibernate first level cache is missed, the answer says "Hibernate does not cache queries and query results by default. The only thing the first level cache is used is when you call EntityManger.find() you will not see a SQL query executing. And the cache is used to avoid object creation if the entity is already loading."
So, if If get an entity not by its Id but other criteria, if I update some property I should not see an update sql inside a transactional methods because it has not been stored int the first level cache, right?
According to the above answer, if I get some list of entities, they will not be stored in first level cache not matter the criteria I use to find them, right?
When a Transactional(propagation= Propagation.NEVER) method loads the same entity by its id two times, is not supposed it will hit the database two times because each loading will run in its own "transaction" and will have its own persistent context? What is the expected behaviour in this case?
Thanks
I just found some really strange behaviour which turns out it is not so strange at all.
My select statement (query from database) worked only the first time. The second time, query from database was cached.
Inside Hub method I read something from database every 10 seconds and return result to all connected clients. But if some API change this data, Hub context does not read actual data.
In this thread I found this:
When you use EF it by default loads each entity only once per context. The first query creates entity instance and stores it internally. Any subsequent query which requires entity with the same key returns this stored instance. If values in the data store changed you still receive the entity with values from the initial query. This is called Identity map pattern. You can force the object context to reload the entity but it will reload a single shared instance.
So my question is how to properly use EFCore inside SignalR Core hub method?
I could use AsNoTracking, but I would like to use some global setting. Developer can easily forget to add AsNoTracking and this could mean serving outdated data to user.
I would like to write some code in my BaseHub class which will tell context do not track data. If I change entity properties, SaveChanges should update data. Can this be achieved? It is hard to think all the time to add AsNoTracking when querying from hub method.
I would like to write some code in my BaseHub class which will tell context do not track data.
The default query tracking behavior is controlled by the ChangeTracker.QueryTrackingBehavior property with default value of TrackAll (i.e. tracking).
You can change it to NoTracking and then use AsTracking() for queries that need tracking. It's a matter of which are more commonly needed.
If I change entity properties, SaveChanges should update data.
This is not possible if the entity is not tracked.
If you actually want tracking queries with "database wins" strategy, I'm afraid it's not possible currently in EF Core. I think EF6 object context services had an option for specifying the "client wins" vs "database wins" strategy, but EF Core currently does not provide such control and always implements "client wins" strategy.
When I use EclipseLink JPA query.getResultList() it doesn't store the results in the cache so when I call merge the first call does a select all then update for each object.
What's the correct all to get query results in the cache?
I'm thinking do the query then call EntityManager find for each result - but seems wrong. Obviously I can't call find first as I don't know the object id.
Basically I want to cache all the data in-memory (in the cache) and have updates as quick as possible.
Thanks
EclipseLink caches every object returned by getResultList() in the shared (L2) cache by default.
If you are not getting caching, then you have mis-configured something.
Please include your code, configuration, and SQL log.
Are you using Spring? (see http://www.eclipse.org/forums/index.php/t/200321/)
Ensure you have not disabled the shared cache, or configured refreshing.
How many object are you reading, and how long is it from the query to the merge? If you are reading a lot of objects, you may need to increase the cache size (default is 100), or change the cache type.
See, http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Caching
I am looking for a way to map stored procedures logically related to a table as functions within the Entity generated for that specific table instead of function in overall Context.
As an example, I have generated edmx out of existing bank database and I got a Context and several entities corresponding to the tables. Assume we have tables for Account, Transactions, Address, etc... and I have a stored proc returning current balance for the account. I want to map this stored proc to the Account entity instead of the context. This will help me to call Account.GetBalance() instead of Context.GetBalance().
Is this possible in entity framework ? I did lot of search and read few articles/blogs in msdn but couldn't find any solution for this.
No it is not possible unless you manually wrap the method exposed on context in your entity - that would make your entities persistence aware and EF dependent which is currently considered as exact opposite of design people should follow.
In terms of EF balance should be property of account entity and retrieving balance should mean reloading account or executing projection query (or your procedure) on accounts set / context. Queries are executed from context and stored procedures as well.