我刚开始编写一个应该使用ormlite来访问我已创建的postgreSQL数据库的应用程序。它使用下面的数据库方案和域对象类。但是,我无法创建一个运行下面的测试方法的新用户。使用此类访问数据库可以正常工作。我得到的异常只是告诉我postgre无法插入:
java.sql.SQLException: Unable to run insert stmt on object net.avedo.spozz.models.User@78412176: INSERT INTO "users" ("id" ,"cdate" ,"mdate" ,"name" ,"email" ,"password" ,"avatar_id" ) VALUES (?,?,?,?,?,?,?)
at com.j256.ormlite.misc.SqlExceptionUtil.create(SqlExceptionUtil.java:22)
at com.j256.ormlite.stmt.mapped.MappedCreate.insert(MappedCreate.java:135)
at com.j256.ormlite.stmt.StatementExecutor.create(StatementExecutor.java:450)
at com.j256.ormlite.dao.BaseDaoImpl.create(BaseDaoImpl.java:310)
at net.avedo.spozz.models.UserTest.testUserCreation(UserTest.java:178)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:264)
at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:153)
at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:124)
at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:200)
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:153)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:103)
Caused by: org.postgresql.util.PSQLException: ERROR: column "cdate" is of type timestamp without time zone but expression is of type character varying
Hint: You will need to rewrite or cast the expression.
Position: 100
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2103)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1836)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:257)
at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:512)
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:388)
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeUpdate(AbstractJdbc2Statement.java:334)
at com.j256.ormlite.jdbc.JdbcDatabaseConnection.insert(JdbcDatabaseConnection.java:170)
at com.j256.ormlite.stmt.mapped.MappedCreate.insert(MappedCreate.java:91)
... 28 more
那么我想念什么?我如何扩展Avatar类以支持像avatar bytea NOT NULL
这样的bytea字段?
postgreSQL数据库方案
CREATE TABLE avatars (
id BIGSERIAL PRIMARY KEY,
cdate TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
mdate TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE users (
id BIGSERIAL PRIMARY KEY,
cdate TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
mdate TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
name VARCHAR(160) UNIQUE NOT NULL,
email VARCHAR (355) UNIQUE NOT NULL,
password VARCHAR(30) NOT NULL,
avatar_id BIGINT,
CONSTRAINT user_avatar_id FOREIGN KEY (avatar_id)
REFERENCES avatars (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
);
一个简单的测试用例
@Test
public void testUserCreation() throws Exception {
try {
// Setup the user database object, ...
Dao<User, Integer> userDao = getUserDao();
// ... create a new user ...
User user = new User();
user.setName("Andi");
user.setEmail("info@avedo.net");
user.setPassword("geheim");
userDao.create(user);
// ... and finally query all users.
List<User> userList = userDao.query(
userDao.queryBuilder().where()
.eq("name", "Andi")
.prepare());
Assert.assertTrue("User creation failed.", userList.get(0).getName().equals("Andi"));
Assert.assertTrue("User creation failed." + userList.get(0).getName(), userList.get(0).getName().equals("Andi"));
} catch (SQLException e) {
throw new Exception("Failed to create user: " + e.getMessage());
}
}
Avatar.java
@DatabaseTable(tableName = "avatars")
public class Avatar {
@DatabaseField(generatedIdSequence = "avatars_id_seq", useGetSet = true)
private long id;
@DatabaseField(canBeNull = false, defaultValue="CURRENT_TIMESTAMP", useGetSet = true)
private String cdate;
@DatabaseField(canBeNull = false, defaultValue="CURRENT_TIMESTAMP", useGetSet = true)
private String mdate;
public Avatar() {
// ORMLite needs a no-arg constructor
}
// Getter and setter methods.
}
User.java
@DatabaseTable(tableName = "users")
public class User {
@DatabaseField(generatedIdSequence = "users_id_seq", useGetSet = true)
private long id;
@DatabaseField(canBeNull = false, defaultValue="CURRENT_TIMESTAMP", useGetSet = true)
private String cdate;
@DatabaseField(canBeNull = false, defaultValue="CURRENT_TIMESTAMP", useGetSet = true)
private String mdate;
@DatabaseField(canBeNull = false, useGetSet = true)
private String name;
@DatabaseField(canBeNull = false, useGetSet = true)
private String email;
@DatabaseField(canBeNull = false, useGetSet = true)
private String password;
@DatabaseField(columnName = "avatar_id", foreign = true, useGetSet = true)
private Avatar avatar;
public User() {
// ORMLite needs a no-arg constructor
}
// Getter and setter methods.
}
答案 0 :(得分:1)
我能够通过将cdate和mdate的属性类型从String
更改为Date
来解决我的问题。此外,我不得不从@DatabaseField注释中删除defaultValue
和canBeNull
参数。这让我接下来的课程:
@DatabaseTable(tableName = "users")
public class User {
@DatabaseField(generatedIdSequence = "users_id_seq", useGetSet = true)
private long id;
@DatabaseField(useGetSet = true)
private Date cdate;
@DatabaseField(useGetSet = true)
private Date mdate;
@DatabaseField(canBeNull = false, useGetSet = true)
private String name;
@DatabaseField(canBeNull = false, useGetSet = true)
private String email;
@DatabaseField(canBeNull = false, useGetSet = true)
private String password;
@DatabaseField(columnName = "avatar_id", foreign = true, useGetSet = true)
private Avatar avatar;
public User() {
// ORMLite needs a no-arg constructor
}
// Getter and setter methods.
}
最后,我必须相应地调整数据库方案:
CREATE TABLE avatars (
id BIGSERIAL PRIMARY KEY,
cdate TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
mdate TIMESTAMP DEFAULT CURRENT_TIMESTAMP
-- avatar bytea NOT NULL
);
CREATE TABLE users (
id BIGSERIAL PRIMARY KEY,
cdate TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
mdate TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
name VARCHAR(160) NOT NULL,
email VARCHAR (355) UNIQUE NOT NULL,
password VARCHAR(30) NOT NULL,
avatar_id BIGINT,
CONSTRAINT user_avatar_id FOREIGN KEY (avatar_id)
REFERENCES avatars (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
);
为了避免NULL值,我将cdate和mdate的默认值设置为CURRENT_TIMESTAMP并添加了一个触发器,如果相应的行发生变化,它将自动更新mdate的值:
CREATE OR REPLACE FUNCTION update_timestamp() RETURNS TRIGGER AS
$update_timestamp$
BEGIN
NEW.mdate := CURRENT_TIMESTAMP;
RETURN NEW;
END;
$update_timestamp$
LANGUAGE plpgsql;
CREATE TRIGGER update_timestamp BEFORE INSERT OR UPDATE ON avatars
FOR EACH ROW EXECUTE PROCEDURE update_timestamp();
CREATE TRIGGER update_timestamp BEFORE INSERT OR UPDATE ON users
FOR EACH ROW EXECUTE PROCEDURE update_timestamp();