问题
I am using embedded glassfish (3.1.2.2) with junit (4.11), with JDK 1.7, though my source and target is set to 1.6 (maven-compiler-plugin configuration).
Following is my code:
Person.java
@Entity
public class Person implements Serializable {
private static final long serialVersionUID = 81398385247591972L;
@Id
@GeneratedValue
private Long id;
@Version
private Long version;
@Column(length = 15, nullable = false, unique = true, updatable = false)
private String username;
@Column(length = 50)
private String status;
// Constructors
// getters/setters
// hashCode, equals, toString
}
Service.java
@Stateless
public class Service {
@PersistenceContext(unitName = "ExamplePU", type = PersistenceContextType.TRANSACTION)
private EntityManager em;
public Person add(Person person) {
em.persist(person);
return person;
}
public Person find(Long id) {
return em.find(Person.class, id);
}
public Person modify(Person person) {
return em.merge(person);
}
// some more code ...
}
ServiceTest.java
public class ServiceTest {
private static EJBContainer ejbContainer;
private static Service service;
// @BeforeClass, @AfterClass, @Before, @After
@Test
public void testMerge() {
Person person;
/* Step 1 */person = service.add(new Person("username", "status"));
print("Added : " + person);
person.setStatus("Away");
/* Step 2 */person = service.modify(person);
print("Merged (status change) : " + person);
person.setUsername("UsErNaMe");
/* Step 3 */person = service.modify(person);
print("Merged (username change) : " + person);
}
// Some more tests
}
Step 1 generates following SQL (as expected):
INSERT INTO PERSON (ID, STATUS, USERNAME, VERSION) VALUES (?, ?, ?, ?)
bind => [1, status, username, 1]
Step 2 generates following SQL (as expected):
UPDATE PERSON SET STATUS = ?, VERSION = ? WHERE ((ID = ?) AND (VERSION = ?))
bind => [Away, 2, 1, 1]
Step 3 does not generate any SQL, but it does not throw any exception, which I am expecting, as the 'username' is annotated as @Column(..., updatable = false). The print(...) method prints following output:
Merged (username change) : Person [id=1, version=2, username=UsErNaMe, status=Away]
This time the merge() operation has updated username, but not version. Also, now the database is out-of-sync with EntityManager cache.
Is this expected, or bug in EclipseLink?
UPDATE
Expected result is exception at Step 3 above.
UPDATE
Have filed bug here.
回答1:
You marked the column as non-updatable, and EclipseLink detects that the only change made to the person you tell it to merge is the user name. But the user name must not be updated. So it doesn't issue any SQL update query.
If you mark a column as non-updatable, you shouldn't update it.
So, to make things clear, the behavior you observe is the expected behavior.
来源:https://stackoverflow.com/questions/15108064/unexpected-behaviour-of-entitymanager-merge