如何创建支持通用 id(包括自动生成的 id)的通用实体模型类?

2023-11-23

我有三个kinds表的主键数:

  • INT自动生成的主键使用AUTO_INCREMENT来自数据库供应商的容量(MySQL)
  • CHAR(X)将用户可读值存储为键的主键(其中 X 是数字且 50
  • 复杂主键,由表的 2 或 3 个字段组成。

此外,还有一些字段可能存在(或不存在):

  • 版本,INT field.
  • 由...制作,VARCHAR(60)字段和lastUpdatedBy,VARCHAR(60)字段(还有更多字段,但这些涵盖了基本示例)。

上面的一些例子:

  • Table1
    • id int 主键自增
    • 版本整数
    • 值字符(10)
    • 创建者:varchar(60)
    • 最后更新者:varchar(60)
  • Table2
    • id char(60) 主键
    • 简短描述 varchar(20)
    • 长描述 varchar(100)
  • Table3
    • field1 int 主键
    • field2 int 主键
    • 金额小数(10, 5)
    • 版本整数

考虑到这一切,我需要创建一组通用类来支持这些要求并允许使用 Hibernate 4.3 和 JPA 2.1 进行 CRUD 操作。

这是我当前的模型(避免使用 getter/setter 以缩短代码示例):

@MappedSuperclass
public abstract class BaseEntity<T> implements Serializable {
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    protected T id;
}

@MappedSuperclass
public abstract class VersionedEntity<T> extends BaseEntity<T> {
    @Version
    protected int version;
}

@MappedSuperclass
public abstract class MaintainedEntity<T> extends VersionedEntity<T> {
    @Column
    protected String createdBy;
    @Column
    protected String lastUpdatedBy;
}

@Entity
public class Table1 extends MaintainedEntity<Long> {
    @Column
    private String value;
}

@Entity
public class Table2 extends BaseEntity<String> {
    @Column
    private String shortDescription;
    @Column
    private String longDescription;
}

我目前正在测试保存实例Table1 and Table2。我有以下代码:

SessionFactory sf = HibernateUtils.getSessionFactory();
Session session = sf.getCurrentSession();
session.beginTransaction();

Table1 newTable1 = new Table1();
newTable1.setValue("foo");
session.save(newTable1); //works

Table2 newTable2 = new Table2();
//here I want to set the ID manually
newTable2.setId("foo_id");
newTable2.setShortDescription("short desc");
newTable2.setLongDescription("long description");
session.save(newTable2); //fails

session.getTransaction().commit();
sf.close();

尝试保存时失败Table2我收到以下错误:

Caused by: java.sql.SQLException: Field 'id' doesn't have a default value
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:996)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3887)

该错误消息很明显,因为CHAR(X)字段没有默认值并且不会有它(AFAIK)。我尝试将生成策略更改为GenerationType.AUTO并收到相同的错误消息。

我如何重构这些类才能支持这些要求?或者更好的是,我如何提供取决于我正在保存的实体的密钥的生成策略,该策略可以自动生成或由我提供?

涉及技术:

  • Java SDK 8
  • 休眠4.3.6
  • JPA 2.1
  • MySQL 和 Postgres 数据库
  • 操作系统:Windows 7 专业版

注意:为了支持 JPA 2.1 的其他实现(例如 EclipseLink),上述内容可能(并且可能将会)发生变化。


没有尝试这个,但根据 Hibernate 的 api,创建自定义实现应该不会变得复杂身份生成器.

它是生成方法 gets 和您要为其生成值的对象,因此您可以检查 id 字段的类型并为主键返回适当的值。

public class DynamicGenerator  implements IdentityGenerator

        public Serializable generate(SessionImplementor session, Object object)
                throws HibernateException {

             if (shouldUseAutoincrementStartegy(object)) { // basing on object detect if this should be autoincrement or not, for example inspect the type of id field by using reflection - if the type is Integer use IdentityGenerator, otherwise another generator 
                 return new IdentityGenerator().generate(seession, object)
             } else { // else if (shouldUseTextKey)

                 String textKey = generateKey(session, object); // generate key for your object

                 // you can of course connect to database here and execute statements if you need:
                 // Connection connection = session.connection();
                 //  PreparedStatement ps = connection.prepareStatement("SELECT nextkey from text_keys_table");
                 // (...)

                 return textKey;

            }

        }
    }

只需将其用作您的生成策略即可:

@MappedSuperclass
public abstract class BaseEntity<T> implements Serializable {
    @Id
    @GenericGenerator(name="seq_id", strategy="my.package.DynamicGenerator")
    protected T id;
}

对于 Hibernate 4,您应该实现IdentifierGenerator界面。


正如 Hibernate 所接受的那样,对于任何“jpa 兼容”提供者来说,应该仍然可以以更通用的方式创建它。根据JPA api中生成值您可以提供自定义生成器的注释。这意味着您可以提供自定义生成器的名称,并且应该为每个 jpa 提供程序实现此生成器。

这意味着您需要使用以下注释来注释 BaseEntity

@MappedSuperclass
public abstract class BaseEntity<T> implements Serializable {
    @Id
    @GeneratedValue(generator="my-custom-generator")
    protected T id;
}

现在,您需要为您想要使用的每个 jpa 提供程序注册名称为“my-custom-generator”的自定义生成器。

对于 Hibernate,这是通过 @GenericGenerator 注释完成的,如前所示(添加@GenericGenerator(name="my-custom-generator", strategy="my.package.DynamicGenerator" to BaseEntity任一个班级id场或BaseEntity班级水平应该足够)。

在 EclipseLink 中,我发现您可以通过以下方式执行此操作生成值注解并通过 SessionCustomizer 注册它:

            properties.put(PersistenceUnitProperties.SESSION_CUSTOMIZER,
                    "my.custom.CustomIdGenerator");

public class CustomIdGenerator extends Sequence implements SessionCustomizer {


    @Override
    public Object getGeneratedValue(Accessor accessor,
            AbstractSession writeSession, String seqName) {
        return  "Id"; // generate the id
    }

    @Override
    public Vector getGeneratedVector(Accessor accessor,
            AbstractSession writeSession, String seqName, int size) {
        return null;
    }

    @Override
    protected void onConnect() {
    }

    @Override
    protected void onDisconnect() {
    }

    @Override
    public boolean shouldAcquireValueAfterInsert() {
        return false;
    }

    @Override
    public boolean shouldOverrideExistingValue(String seqName,
            Object existingValue) {
        return ((String) existingValue).isEmpty();
    }

    @Override
    public boolean shouldUseTransaction() {
        return false;
    }

    @Override
    public boolean shouldUsePreallocation() {
        return false;
    }

    public void customize(Session session) throws Exception {
        CustomIdGenerator sequence = new CustomIdGenerator ("my-custom-generator");

        session.getLogin().addSequence(sequence);
    }

}    

每个提供程序都必须提供一种注册 id 生成器的方法,因此如果您想支持所有提供程序,则需要为每个提供程序实现并注册自定义生成策略。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何创建支持通用 id(包括自动生成的 id)的通用实体模型类? 的相关文章

随机推荐

  • preg_replace() 会改变我的字符集吗?

    我有以下代码似乎正在改变我的字符集 html echo html result html preg replace s html echo html result 但是 当我使用 t n r f v 作为我的模式而不是特殊字符 s它工作正常
  • Bluemix 新手,新应用程序出现错误“主机已被占用”

    我是 Bluemix 的新手 按照以下步骤创建应用程序 使用您的 Bluemix 帐户登录 Bluemix 打开目录菜单 从运行时部分 单击 Liberty for Java 在应用程序字段中 指定您的应用程序的名称 输入姓名 单击创建按钮
  • 覆盖Android后退按钮

    关于我为什么尝试这样做的一些信息 我正在使用 ActivityGroups 从 tabHost 活动打开一个活动 并将该新活动保留在选项卡下 那部分我已经有了 但是 在该新活动中 如果我使用后退按钮 它会将我直接退出选项卡活动 因此我必须单
  • 没有 'owned by' 属性的 Postgres 序列在 Django 1.3 中不会返回 id

    最近从 Oracle 迁移到 Postgres 并从 Django 1 2 升级到 1 3 后 我们在将对象保存到数据库时开始遇到问题 当调用 save 时 不会返回 id 即使通过标准 django 管理面板保存标准 django aut
  • android:选择图库中的多个图像并启动隐式意图

    如何获取所有选定图像的图像路径或仅将它们显示在我的应用程序中 当用户在图库中选择图像并按共享按钮时 我可以启动隐式意图并将其显示在我的 imageView 中 如下所示 ImageView iv ImageView findViewById
  • 将时间序列数据提供给有状态 LSTM 的正确方法?

    假设我有一个整数序列 0 1 2 并希望根据最后 3 个整数来预测下一个整数 例如 0 1 2 gt 5 3 4 5 gt 6 etc 假设我像这样设置模型 batch size 1 time steps 3 model Sequentia
  • 钩住时间编织块

    我想对 knitr 块进行计时 并记录使用 LaTeX 输出中的注释渲染它们所花费的时间 我尝试过以下钩子 now Sys time knit hooks set timeit function before if before now l
  • JavaScript 函数表达式前面的加号

    我一直在寻找有关立即调用函数的信息 在某个地方我偶然发现了这个符号 function console log Something 有人可以向我解释一下是什么吗 函数前面的符号意味着 做什么 它强制解析器处理以下部分 作为一种表达方式 这通常
  • 将边框应用于图像形状

    在我的应用程序中 我有不同形状的各种图像 如树 云 附有示例图片 我想以编程方式为这些形状添加边框 就像如果图像是树那么需要突出显示树的形状 我无法使用 callayer 因为它会将边框应用于 UIImageView 谁能指导我如何实现这一
  • GCC下未定义的引用与LTO交叉编译静态库

    我正在尝试使用 GCC 4 9 2 从 Linux x86 64 pc linux gnu 交叉编译 Windows x86 64 w64 mingw32 的应用程序 当构建链接到静态库的目标并使用链接时优化时 我从链接器中得到目标从库中使
  • 评估 Main(string[] args) 是否太过分了

    我有以下内容 想知道初始测试是否过度 static void Main string args if args Length 0 args null do X else do Y 换句话说 我要问的是 args Length 是否有可能为零
  • 如何在android 4.0 ICS中启用底部菜单按钮

    I want to enable bottom menu button and Which theme will be use for this menu button I try many theme but did not work f
  • 如何处理和提取图像中的文本

    我正在尝试使用 python cv2 从图像中提取文本 结果是可悲的 我找不到改进我的代码的方法 我相信在提取文本之前需要处理图像 但不确定如何处理 我尝试将其转换为黑白 但没有成功 import cv2 import os import
  • Jetpack Compose 性能问题仅发生在多模块项目中

    我在 Jetpack Compose 中开发了一个相当复杂的键盘布局 最初 布局工作正常 按下按键时动画运行非常流畅 不幸的是 由于事件而进行了几次重组之后 动画和一切都变得非常缓慢和滞后 我尝试对 Jave 方法调用进行采样 但我只能看到
  • Couchbase 4010 错误

    我一直在测试 Couchbase 5 并创建了一个名为fp conversion data其中包含一些 JSON 数据 我一直在尝试运行一些简单的查询 例如 SELECT FROM fp conversion data limit 5 我没
  • 移出的物体是否需要销毁?

    如果我移动构建a from b 还是吗必要的破坏b 或者我可以不这样做就逃脱吗 这个问题在实施过程中闪过我的脑海optional
  • 如何只保留数组中符合特定条件的项?

    我有一个数组 我想过滤它以仅包含符合特定条件的项目 这可以用 JavaScript 完成吗 一些例子 1 2 3 4 5 6 7 8 I only want 2 4 6 8 i e the even numbers This is an a
  • 如何在 Webkit GTK 中处理自定义 URL 方案?

    假设我想使用WebKitWebView在 GTK 中显示一些静态 HTML 页面 这些页面使用自定义 URL 方案 我们称之为custom 此方案表示一个本地文件 在生成 HTML 时 其位置事先未知 我所做的就是连接到navigation
  • 安卓中的AT命令

    我想在我的应用程序中使用 AT 命令来设置 GSM 调制解调器的一些命令 我搜索了谷歌 但找不到任何好的答案 你有什么解决办法吗 我可以使用ADB向android发送AT命令吗 首先你必须root手机然后在adb shell中 su ech
  • 如何创建支持通用 id(包括自动生成的 id)的通用实体模型类?

    我有三个kinds表的主键数 INT自动生成的主键使用AUTO INCREMENT来自数据库供应商的容量 MySQL CHAR X 将用户可读值存储为键的主键 其中 X 是数字且 50 复杂主键 由表的 2 或 3 个字段组成 此外 还有一