JPA - Trả lại id được tạo tự động sau khi Kiên trì ()


113

Tôi đang sử dụng JPA (EclipseLink) và Spring. Giả sử tôi có một thực thể đơn giản với ID được tạo tự động:

@Entity
public class ABC implements Serializable {
     @Id
     @GeneratedValue(strategy=GenerationType.IDENTITY)
     private int id;

     // ...
}

Trong lớp DAO của mình, tôi có một phương thức chèn gọi persist()thực thể này. Tôi muốn phương thức trả về ID đã tạo cho thực thể mới, nhưng khi tôi kiểm tra nó, nó sẽ trả về 0thay thế.

public class ABCDao {
    @PersistenceContext
    EntityManager em;

    @Transactional(readOnly=false)
    public int insertABC(ABC abc) {
         em.persist(abc);
         // I WANT TO RETURN THE AUTO-GENERATED ID OF abc
         // HOW CAN I DO IT?
         return abc.id; // ???
    }
}

Tôi cũng có một lớp dịch vụ bao bọc DAO, nếu điều đó tạo ra sự khác biệt:

public class ABCService {
    @Resource(name="ABCDao")
    ABCDao abcDao;

    public int addNewABC(ABC abc) {
         return abcDao.insertABC(abc);
    }
}

Tương tự, có thể tham khảo stackoverflow.com/q/3328813/366964
Nayan Wadekar

Cảm ơn vì những câu trả lời. Và như một giải pháp phức tạp (không phải JPA), chúng ta có thể sử dụng một id duy nhất khác như dấu thời gian unix.
sura2k

Câu trả lời:


184

ID chỉ được đảm bảo sẽ được tạo tại thời điểm thay thế. Việc duy trì một thực thể chỉ làm cho nó "được gắn" vào ngữ cảnh tồn tại. Vì vậy, hãy xóa người quản lý thực thể một cách rõ ràng:

em.persist(abc);
em.flush();
return abc.getId();

hoặc trả về chính thực thể thay vì ID của nó. Khi giao dịch kết thúc, quá trình xóa sẽ xảy ra và người dùng của thực thể bên ngoài giao dịch do đó sẽ thấy ID được tạo trong thực thể.

@Override
public ABC addNewABC(ABC abc) {
    abcDao.insertABC(abc);
    return abc;
}

10
NB: điều này cần chú thích trường id với @GeneratedValue- bất cứ điều gì yêu cầu
Mr_and_Mrs_D

Bạn có thể vui lòng giải thích các vấn đề trong việc cố gắng đạt được điều này với id tổng hợp stackoverflow.com/questions/31362100/…
bl3e

Có hình phạt hiệu suất (hoặc bất kỳ tác động tiêu cực nào khác) của việc xả nước thủ công sau khi kiên trì không?
Craig Otis

3
Có, có: vòng lặp không cần thiết đối với cơ sở dữ liệu nếu giao dịch kết thúc được khôi phục, có thể có các ngoại lệ nếu thực thể được duy trì (hoặc các thực thể được xóa khác) chưa ở trạng thái hợp lệ. Trình tạo trình tự hoặc trình tạo uuid đơn giản hơn và hiệu quả hơn và không gặp phải những vấn đề này vì ID được tạo và gán trước khi thực thể được ghi vào cơ sở dữ liệu.
JB Nizet

1
@JBNizet, bạn có cần trả lại phiên bản không hay tham chiếu đã chuyển vẫn hợp lệ? Ý tôi là, có insertABCtạo một đối tượng mới không? Hay sửa đổi cái cũ?
ryvantage

13
@Entity
public class ABC implements Serializable {
     @Id
     @GeneratedValue(strategy=GenerationType.IDENTITY)
     private int id;   
}

kiểm tra xem ký hiệu @GeneratedValue có trong lớp thực thể của bạn hay không. Điều này cho JPA biết về hành vi được tạo tự động thuộc tính thực thể của bạn


4

Đây là cách tôi đã làm điều đó:

EntityManager entityManager = getEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
entityManager.persist(object);
transaction.commit();
long id = object.getId();
entityManager.close();

Nó không hoạt động với số không dưới dạng Trả lại sau khi kiên trì dữ liệu vào bảng. hoặc làm mới không hoạt động trong trường hợp này .. Tôi nên làm gì cho điều này. xin đề nghị một cách ... Cảm ơn bạn
Vikrant Kashyap

1
@VikrantKashyap Vui lòng đăng một câu hỏi mới với mã nhỏ và đề cập đến tôi để tôi có thể xem xét.
Koray Tugay

2

Bạn cũng có thể sử dụng GenerationType.TABLE thay vì IDENTITY chỉ khả dụng sau khi chèn.


2
Chỉ cần một lời cảnh cáo. Khi tôi thử GenerationType.TABLE, nó đã tạo một bảng riêng biệt có tên hibernate_sequences và khởi động lại trình tự từ 1.
SriSri

0

Một tùy chọn khác tương thích với 4.0:

Trước khi thực hiện các thay đổi, bạn có thể khôi phục CayenneDataObject(các) đối tượng mới từ bộ sưu tập được liên kết với ngữ cảnh, như sau:

CayenneDataObject dataObjectsCollection = (CayenneDataObject)cayenneContext.newObjects();

sau đó truy cập ObjectIdcho từng cái trong bộ sưu tập, như:

ObjectId objectId = dataObject.getObjectId();

Cuối cùng, bạn có thể lặp lại dưới các giá trị, trong đó thường id được tạo sẽ là giá trị đầu tiên (cho một khóa cột duy nhất) trong Bản đồ được trả về getIdSnapshot(), nó cũng chứa (các) tên cột được liên kết với PK dưới dạng (các) khóa:

objectId.getIdSnapshot().values()

0

Đây là cách tôi đã làm điều đó. Bạn co thể thử

    public class ABCService {
    @Resource(name="ABCDao")
    ABCDao abcDao;

    public int addNewABC(ABC abc) {
         ABC.setId(0);
         return abcDao.insertABC(abc);
    }
}

-3
em.persist(abc);
em.refresh(abc);
return abc;

Phương pháp này không làm việc cho tôi. Nhận lỗi này: javax.persistence.PersistenceException: org.hibernate.HibernateException: trường hợp này chưa tồn tại như một hàng trong cơ sở dữ liệu]
rtcarlson

@rtcarlson, có, điều này sẽ không hoạt động. nếu bạn đang tạo một đối tượng mới, những gì bạn cần em.flush()không phải là em.refresh(abc).
Ibrahim Dauda
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.