Unexpected behaviour of EntityManager.merge()

人盡茶涼 提交于 2019-12-12 06:15:31

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!