when persisting (updating) an entity you would call EntityManager.persist(entity) passing the complete entity. It is possible to intercept with #PreUpdate.
Does anyone have a recipe how to identify which properties have changed in this interceptor method ? Somehow comparing the old and the new entity ? Even better to implement a generic method instead of comparing field by field for each class.
Thanks for any input !
Sven
First of all, persist() is for new objects (insert) not update. Any object changed in the persistence context will be automatically updated.
JPA does not provide any standard way to know what changed. So you either need to track changes yourself, or use a JPA provider specific API.
In EclipseLink if you use the EclipseLink DescriptorEventListener preUpdate event instead of the JPA one, you get an ObjectChangeSet attached to the DescriptorEvent which contains the changes.
Another way in JPA, if you are using weaving, is to cast your object to ChangeTracker and call _persistence_getPropertyChangeListener() then getObjectChangeSet().
If you are using TopLink Essentials the descriptor events also apply, but change tracking was not weaved.
Related
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.
In my application I need most objects fetched in detached mode (fetched with the find API).
I'm wondering if there is a way to ask a detached object from the JPA provider and save the extra call to detach() API.
In additional I would expect the object created in such mode to be less expensive since the JPA provider doesn't need to add it to the entity manager context.
Is there a way to achieve this with JPA APIs?
Is there a way to achieve such functionality with query results?
Specifically I'm using Eclipse Link so if there is a specific way to do it with this implementation it will be helpful as well.
You can fetch a detached entity without an extra call to detach() if you fetch it outside a transaction. If you are not using container-managed transactions, it's trivial, simply do not start a transaction.
If you are using CMT, you have to make sure the requesting object is not a transaction-enabled EJB:
if in an EJB, suspend the transaction by annotating the appropriate method with:#TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED),
or
call the EntityManager from a POJO. You dont have to call it directly, it only impotrant that the query result will end in a non-EJB object.
AFAIK, there is no performance gain to be expected, since the query result will always be put in the current persistence context, however shortlived it may be.
EDIT: There is another possibility to get detached objects which does not depend on transaction demarcations: JPA constructor expressions:
List<DTO> dtos = em.createQuery("SELECT NEW com.example.DTO( o.title, o.version) FROM Entity o").getResultList();
The constructed type must have a constructor with all the relevant attributes. The objects in the list, entities or not, will always be created detached. However there is a small overhead of instantiating a new object.
I'm writing my first GWT-Application and need your advice. I have no problems implementing a locator for database entities where I can reuse the version-column used for optimistic locking by hibernate, but one of my entities represents a ldap-Object. Can you tell me what the method getVersion() of the Locator is used for and how I can implement this method for my ldap-Object? I will do read and write ldap objects.
From GWT documentation, getVersion method is
Used by RequestFactory to infer if an entity has changed. The backing store (JDO, JPA, etc.) is responsible for updating the version each time the object is persisted, and RequestFactory calls getVersion() to learn of changes. This information is used in two places. First, the RequestFactoryServlet sends an UPDATE event to the client if an entity changes as a result of the method invocation on the server, for example, when a call to persist an editable entity results in an updated version on the server. Second, the client maintains a version cache of recently seen entities. Whenever it sees an entity whose version has changed, it fires UPDATE events on the event bus so that listeners can update the view.
Since many persistence frameworks offer generic find/get/query methods, it's also possible to create a generic Locator class and specify it in the #ProxyFor annotation for each entity type. To do this, all your entities can extend a base class that provides getId() and getVersion(). Alternatively, the generic Locator can use reflection to call getId() and getVersion() when needed.
Not sure if you're looking for anything else in addition to this.
I have the same problem. My first thought was to use the Attribute modifyTimestamp and createTimestamp. But there is still a functional gap:
The smallest unit of These timestamps is seconds so a Change in the same second can not be detected. Another solution would be to use a kind of checksum over all attributes of the ldap object. Not very nice..
I am using Entity Frameworks Code First. I have one entity that I need to keep a change history on. This entity has a double property and when it changes I need to record the amount change amount and date that it occurred. This means I need the old value the new value subtract and post ever time that value changes or when dbContect.SaveChanges() it called.
This project is really simple and I would like to keep it this way so I would prefer not add a service layer. I am simply making repository request in MVC controllers. (I know this is not pure but it is very agile)
How can I intercept changes to this entity so I can write to a change log?
You can listen for the ObjectContext.SavingChanges event, and then use the ObjectContext.ObjectStateManager property to look for the ObjectStateEntry(s) for the entity type that you are interested in.
ObjectStateEntry has properties to access the CurrentValues and OriginalValues, or only the original values for updatable properties using the GetUpdatableOriginalValues method.
Note: I have not tested this, but hopefully it will work for you.
I wonder if anyone can help me?
I am having problems understanding why i need to issues DetectChanges on my POCO (non proxy) entities.
Of course i have this line to ensure that proxies are not returned.
context.ObjectStateManager.GetObjectStateEntry(order).State
And doing some research it appears if i need to check the "state" of an object then i need to issue detechChanges But why would i need to check the State of an object?
Basically I send along my POCO entity to a method that SAVES the data to a new ObjectContext (I create and destroy ObjectContext on each method)
Hence, i am having problems understanding why i would need to have ObjectContext track or be aware of changes?
Is it because that if its not aware if will not be saved?
Maybe i am miss informed but it appears that if i am using an existing ObjectContext (which i am not i am creating and destroying each time) that ensure ObjectContext is aware would be beneficial but otherwise not?
So in 1 method I am updating an object by creating a new datacontext, saving it to the db and destroying ObjectContext . Hence i am not using 2 methods, 1 method to send the update or new record and then another method for SAVING.
I would really appreciate any quick explaanations of why its needed?
Thanks in advance
Your question is little bit confusing. You are writting about Entity Framework but using DataContext which is related to LinqToSql.
The behavior differs in the way you are using ObjectContext. When you load POCO entity from database ObjectContext holds its instance in internal Identity Map. By default POCO doesn't use any kind of change tracking. When you save that POCO entity to the same instance of ObjectContext it internally calls DetectChanges to compare current entity state with stored state. This comparision defines which columns have to be updated. Internal call to DetectChanges is default behavior which can be turned off so you will have to call this method manually.
In your scenario you not using the same instance of ObjectContext. In that case you first have to Attach POCO entity to the ObjectContext. MSDN strictly says that when attaching entity it is marked as Unchanged. For that reason you have to say ObjectContext that entity has changed. You can do that for whole entity or you can define exactly which properties have changed but you have to do it manually = you have to store that information somewhere (Self tracking entities can help you with that but they have ohter disadvantages).