ChatGPT解决这个技术问题 Extra ChatGPT

JPA - 在persist()之后返回自动生成的ID

我正在使用 JPA (EclipseLink) 和 Spring。假设我有一个带有自动生成 ID 的简单实体:

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

     // ...
}

在我的 DAO 类中,我有一个在此实体上调用 persist() 的插入方法。我希望该方法返回为新实体生成的 ID,但是当我测试它时,它会返回 0

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; // ???
    }
}

我还有一个包装 DAO 的服务类,如果这有所作为:

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

    public int addNewABC(ABC abc) {
         return abcDao.insertABC(abc);
    }
}
类似的,可以参考stackoverflow.com/q/3328813/366964
感谢您的回答。作为一个棘手的解决方案(不是 JPA),我们可以使用另一个唯一的 id,比如 unix 时间戳。
请参考下面的链接,看起来同样的问题stackoverflow.com/questions/9732453/…

J
JB Nizet

ID 只保证在刷新时生成。持久化一个实体只会使其“附加”到持久化上下文。因此,要么显式刷新实体管理器:

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

或返回实体本身而不是其 ID。当事务结束时,将发生刷新,事务外实体的用户将因此在实体中看到生成的 ID。

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

注意:这需要用 @GeneratedValue 注释 id 字段 - 无论需要什么
您能解释一下尝试使用复合 ID stackoverflow.com/questions/31362100/… 实现这一目标的问题吗
持久化后手动刷新是否有性能损失(或任何其他负面影响)?
是的,有:如果事务最终被回滚,则不必要的数据库往返,如果持久实体(或其他刷新的实体)尚未处于有效状态,则可能出现异常。序列或 uuid 生成器更简单、更高效,并且不存在这些问题,因为 ID 是在实体写入数据库之前生成和分配的。
@JBNizet,您需要返回实例还是传递的引用仍然有效?我的意思是,insertABC 会创建一个新对象吗?还是修改旧的?
u
utkal patel
@Entity
public class ABC implements Serializable {
     @Id
     @GeneratedValue(strategy=GenerationType.IDENTITY)
     private int id;   
}

检查您的实体类中是否存在 @GeneratedValue 表示法。这会告诉 JPA 您的实体属性自动生成的行为


K
Koray Tugay

我是这样做的:

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

将数据持久保存到表中后,它无法将零作为返回值。在这种情况下,刷新都不起作用..我该怎么办。请提出一种方法...谢谢
@VikrantKashyap 请用小代码发布一个新问题并提及我,以便我看看。
J
James

您还可以使用 GenerationType.TABLE 而不是 IDENTITY,后者仅在插入后可用。


只是一个警告。当我尝试 GenerationType.TABLE 时,它创建了一个名为 hibernate_sequences 的单独表并从 1 重新启动序列。
e
emecas

与 4.0 兼容的另一个选项:

在提交更改之前,您可以从关联到上下文的集合中恢复新的 CayenneDataObject 对象,如下所示:

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

然后访问集合中每个元素的 ObjectId,例如:

ObjectId objectId = dataObject.getObjectId();

最后,您可以在值下进行迭代,通常生成的 ID 将是 getIdSnapshot() 返回的 Map 中的第一个值(对于单个列键),它还包含关联的列名以 PK 作为密钥:

objectId.getIdSnapshot().values()

A
Anh Khoa

我就是这样做的。你可以试试

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

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

所以每次你在数据库上插入东西时你应该设置那个id?应该有更好的方法,无需您设置 ID
一旦记录被持久化,id由hibernate设置
A
Andrey
em.persist(abc);
em.refresh(abc);
return abc;

这种方法对我不起作用。得到这个错误:javax.persistence.PersistenceException: org.hibernate.HibernateException: 这个实例在数据库中还没有作为一行存在]
@rtcarlson,是的,这行不通。如果您要创建一个新对象,您需要的是 em.flush() 而不是 em.refresh(abc)

关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅