I am experiencing a strange intermittent issue with JPA/Hibernate and MySQL 5.7. I'm looking for suggestions.
My entity is defined with:
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "created_at", nullable = false)
protected Date createdAt;
which translates to the following SQL table definition:
`created_at` DATETIME NOT NULL
and the timestamp is set upon entity creation using
#PrePersist
protected void onCreate() {
updatedAt = createdAt = new Date();
}
JPA save operation sometimes leads to SQL error due to null value being supposedly sent in UPDATE query via Spring CRUD rest repository.
I have verified the post request includes the created_at field, but more importantly, the following screenshot of my log feed confirms that the created_at value is present. However subsequent save blows out. (There is only one "createdAt" field if anyone wondered):
Note: The AOP advices are used for spring-acl integration and don't manipulate entity data (they do provide a convenient interception for logging purposes as seen in the screenshot above).
I can't reliably replicate the error. What could be the reason behind this strange behaviour? I thought second level caching - tried disabling #Cacheable on the entity, but to no avail. Enabling detailed logging with SQL binding is not practical due to irregular nature of the issue.
Related
We have a ASP.NET MVC 3 C# project running NHibernate 3 and Castle.ActiveRecord for MySQL, and we trying to get "one session per request" to work with this tutorial.
And it seems to work for some stuff, but when we do SaveAndFlush(), the command gives us an error:
A different object with the same identifier value
was already associated with the session: 142
And if we try to do only Save() we got the same message so it has nothing to do with the Flush() function.
I have find some result when I search but nothing I can use to get it to work.
Something I have not tested because I don't know how I do, is,
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
Any ideas?
Basically the problem might lie in that you are trying to Save() an object that already exists. If the object has an identifier already set (object.Id = 142) then the object does not need to be saved.
If you make changes to it, and need to save those changes you need to use the Update() method (as mentioned by #OskarBerggren) or the SaveOrUpdate() which basically checks and decides whether to save the object or update it. The last one might work best in your case. Change your current,
session.Save(object);
to,
session.SaveOrUpdate(object);
The Session object is from NHibernate's SessionFactory implementation. However, I see you are using ActiveRecordMediator, so you can use,
ActiveRecordMediator.GetSessionFactoryHolder().CreateSession()
to create a Session you can use to save your models.
I have a Spring / Hibernate project and I am trying to store a date into the database but it's not working. It must be something stupid but I have no idea what I am doing wrong.
Here is my code:
user.setFailedPasswordAnswerAttemptCount(0);
user.setLastLoginDate(new Date());
user.setIsOnline(true);
The other two variables (failedPasswordAnswerAttemptCount and isOnline) are getting written to the database without issue. I have also tried it with just passing a java.util.Date instead of a java.sql.Timestamp...same result. Here is how the property is defined on the user object:
private Date lastLoginDate;
#Temporal(TemporalType.TIMESTAMP)
#Column(name="last_login_date")
public Date getLastLoginDate() {
return this.lastLoginDate;
}
public void setLastLoginDate(Date lastLoginDate) {
this.lastLoginDate = lastLoginDate;
}
Here is the column definition:
`last_login_date` datetime DEFAULT NULL
Any help? I don't even know what else to look for as this should be working.
Some more detail about the error: No errors or strange messages in the hibernate log. The hibernate log is showing a parameterized query but it isn't telling me what it is actually writing. It looks like it's not updating the column at all. In other words, if there is already a date there it doesn't change, or if it is null it doesn't change.
Update: I have looked at the logs and it looks like hibernate does write the proper data, but then immediately writes the incorrect data again. I see the following entry in the log:
11:15:12.280 [http-bio-8080-exec-26] TRACE o.h.e.def.AbstractSaveEventListener - detached instance of: com.hi.model.User
11:15:12.280 [http-bio-8080-exec-26] TRACE o.h.e.def.DefaultMergeEventListener - merging detached instance
And right after that I see it putting the old value back in for the lastLoginDate.
Why are you using
Date date = new Date();
user.setLastLoginDate(new Timestamp(date.getTime()));
and not just this?
user.setLastLoginDate(new Date());
First - You may not want to use Date and Timestamp at the same time.(e.g. for collections, etc)
There are some classes in the Java platform libraries that do extend an instantiable
class and add a value component. For example, java.sql.Timestamp
extends java.util.Date and adds a nanoseconds field. The equals implementation
for Timestamp does violate symmetry and can cause erratic behavior if
Timestamp and Date objects are used in the same collection or are otherwise intermixed.
The Timestamp class has a disclaimer cautioning programmers against
mixing dates and timestamps. While you won’t get into trouble as long as you
keep them separate, there’s nothing to prevent you from mixing them, and the
resulting errors can be hard to debug. This behavior of the Timestamp class was a
mistake and should not be emulated. (Bloch, Effective Java, 2nd Ed.)
Second - I checked your examples, and it works fine for me on mysql-connector(5.1.21) / hibernate (4.0.1)
I prepared simple test project with arquillian integration test(You need to prepare jboss before running it):
https://github.com/rchukh/StackOverflowTests/tree/master/13803848
If you can provide some more information it might help - hibernate version, mysql version, mysql engine(MyISAM, InnoDB, etc.)
Otherwise it is possible that this is just a misconfiguration.
I found the problem. I am refactoring some code and it looks like I was doing this:
//get user object
User user = getUser();
//call a function which modifies user
functionModifiesUser();
//modify user
user.blah = blah;
entityManager.merge(user);
So the parent function had a stale copy of the user object when I tried to save it. Actually, removing the merge statement was enough to fix it. But I have refactored the code to put all this in one place.
Setting the column last_login_date as timestamp should work, at least works for me.
I have a standard update happening via linq to sql but the data does not persist to the database.
I am using an auto-generated class via the .dbml file designer.
The update statement is below:
public static void UpdateEmailsInWorkingTable(Guid emailGuid, string modifiedEmail)
{
using (EmailDBDataContext DBContext = new EmailDBDataContext())
{
EmailAddress_Update EAUpdated = (from e in DBContext.EmailAddress_Updates
where e.EmailGuid == emailGuid
select e).SingleOrDefault();
EAUpdated.EmailAddress = modifiedEmail;
EAUpdated.IsValid = 'Y';
EAUpdated.UpdateFlag = true;
EAUpdated.LastChangedDtTm = DateTime.Now;
try
{
DBContext.SubmitChanges(ConflictMode.FailOnFirstConflict);
}
catch (ChangeConflictException ex)
{
// do stuff here
}
}
}
I looked through my auto-generated DataContext class and the only glaring difference is that the table in question EmailAddress_Update does not implement the two interfaces INotifyPropertyChanging and INotifyPropertyChanged that the other auto-generated entities do.
I am assuming that this is the cause of why the changes are not being persisted is it not???
To put it simply none of the Extensibility Method Definitions get generated for any part of this one class. If this is the cause of my problems, what in the database would be causing this to not auto-generate properly??
Thanks~
I posted this question on MSDN as well here: MSDN Linq to Sql if you wanted to see the replies. But I found part of the reason why the code doesn't generate.
Here is a piece from my MSDN response:
I created a small test table without a primary key and added it to the designer and sure enough it didn't generate any of the Extensibility methods for that instance.
So I then added a primary key to the same table and re-added it to the designer and sure enough all of the extensibility methods and change tracking events were generated.
My question now is why must there be a primary key for this stuff to auto-generate?
Ok so to answer my own question "My question now is why must there be a primary key for this stuff to auto-generate?" I found it in the book Pro LINQ written by Joe Joseph C. Rattz, Jr.
I was reading how to handle views versus tables and he says this:
"Because the entity classes generated for views do not contain entity class properties that are mapped as primary keys, they are read-only. If you consider that without primary keys, the DataContext has no effective way to provide identity tracking, this makes sense."
Mystery and problem solved.
System.Data.Linq.ChangeConflictException: 2 of X updates failed.
at System.Data.Linq.ChangeProcessor.SubmitChanges(ConflictMode failureMode)
at System.Data.Linq.DataContext.SubmitChanges(ConflictMode failureMode)
at PROJECT.Controllers.HomeController.ClickProc(Int32 id, String code, String n)
This is what I get very often. This action is done thousands of times a day, and I get this exception about once every 5 seconds. From what I understand it happens when something changes in the database in the period between creating DataContext and updating it. Am I right?
How can I fix it?
Update
I just debugged the error and found the following:
Table name: dbo.Stats
current value: 9852039
original value: 9852038
database value: 9852039
The Stats table is updated constantly. So how can I still make LINQ save the changes. With "classical" SQL Server access through SqlDataCommand I never had problems like that.
This is due to optimistic concurrency. You can change this behavior but understand what it does before you do it.
https://blogs.msdn.microsoft.com/matt/2008/05/22/intro-to-linq-to-sql-optimistic-concurrency/
I'm learing LINQ-to-SQL right now and i have wrote a simple application that define SQL data:
[Table( Name = "items" )]
public class Item
{
[ Column( IsPrimaryKey = true, IsDbGenerated = true ) ]
public int Id;
[ Column ]
public string Name;
}
I have launched 2 copy of application connected to the same .sdf file and tested if all database modifications in one application affects another application. But strange thing arise. If i use InsertOnSubmit() and DeleteOnSubmit() in one application, added/removed items are instantly visible in other application via 'select' LINQ queue. But if i try to modify 'Name' field in one application, it is NOT visible in other applicaton until it reconnects the database :(. The test code i use:
var Items = from c in db.Items
where Id == c.Id
select c;
foreach( var Item in Items )
{
Item.Name = "new name";
break;
}
db.SubmitChanges();
Can anyone suggest what i'm doing wrong and why InsertOnSubmit()/DeleteOnSubmit works and SubmitChanges() don't?
This is related to how Linq-to-Sql manages Object Identity. If you query for the same entity more than once, you will always receive the same object representing the row in the database.
When you insert or delete entities, you are able to see the changes from another client because Linq-to-Sql will need to create/delete the objects associated with those entities and, if there are no conflicts, this presents no problem.
Updating has a different behavior that's explained in the Object Identity article.
LINQ to SQL uses this approach to
manage the integrity of local objects
in order to support optimistic
updates. Because the only changes that
occur after the object is at first
created are those made by the
application, the intent of the
application is clear.
If you need the most updated data from the database, use the DataContext.Refresh with RefreshMode.OverwriteCurrentValues.