2012-05-16 17 views
0

我有兩個類PLibObject和PLibEntry。 PLibObject可以有幾個PLibEntries。 PLibEntry只能有一個PLibObject。當以1:n關係存儲對象時ConstraintViolationException

使用PLibEntry存儲PLibObject時會引發ConstraintViolationException(請參閱底部的例外情況)。

@Entity 
@Table(name = "pla_objects") 
public class PLibObject { 

    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private int id; 
    @Column(name = "plibid", unique = true, nullable = false) 
    private String plibId; 
    @Column(name = "oid", nullable = false) 
    private String oid; 
    @OneToMany(mappedBy = "pLibObject", orphanRemoval = true, cascade = CascadeType.ALL) 
    private Set<PLibEntry> pLibEntries = new HashSet<PLibEntry>(); 
    ... 


@Entity 
@Table(name = "pla_entries") 
public class PLibEntry { 

    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private int id; 
    @Column(name = "entryid", unique = true, nullable = false) 
    private String entryId; 
    @Column(name = "userid", nullable = false) 
    private int userId; 
    @ManyToOne(optional = false, cascade = CascadeType.ALL) 
    @JoinColumn(name = "plibid") 
    private PLibObject pLibObject; 
    @Temporal(TemporalType.TIMESTAMP) 
    @Column(name = "creationdate", nullable = false) 
    private Date creationDate; 
    @Column(name = "sharedfrom", nullable = false) 
    private String sharedFrom; 
    @Enumerated(EnumType.STRING) 
    @Column(name = "sharingstatus", nullable = false) 
    private SharingStatus sharingStatus; 
    @ElementCollection 
    @CollectionTable(name = "pla_tags", joinColumns = @JoinColumn(name = "entryid")) 
    @Column(name = "tag") 
    private Set<String> tags; 
    ... 

public enum SharingStatus { 
    UNSHARED, 
    SHARING_PENDING, 
    SHARING_ACCEPTED, 
    SHARING_CANCELLED_BY_SHARER; 
} 

數據庫表(MySQL的):

create table pla_objects(
    id int(10) not null auto_increment, 
    plibid varchar(255) not null, 
    oid varchar(255) not null, 
    primary key (id), 
    unique (plibid) 
) charset=utf8 engine=innodb; 

create table pla_entries(
    id int(10) not null auto_increment, 
    entryid varchar(255) not null, 
    userid int(10) not null, 
    plibid varchar(255) not null, 
    creationdate datetime not null, 
    sharedfrom varchar(255), 
    sharingstatus enum('UNSHARED', 'SHARING_PENDING', 'SHARING_ACCEPTED', 'SHARING_CANCELLED_BY_SHARER') not null, 
    primary key (id), 
    unique (entryid), 
    foreign key (plibid) references pla_objects(plibid) 
) charset=utf8 engine=innodb; 

create table pla_tags(
    entryid varchar(255) not null, 
    tag varchar(255) not null, 
    primary key (entryid, tag), 
    foreign key (entryid) references pla_entries(entryid) 
) charset=utf8 engine=innodb; 

例外:產生異常

javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: Referentielle Integrität verletzt: "CONSTRAINT_B23: PUBLIC.PLA_ENTRIES FOREIGN KEY(PLIBID) REFERENCES PUBLIC.PLA_OBJECTS(PLIBID) 

代碼(只是爲了測試目的,真正的實現要複雜得多):

PLibObject pLibObject = new PLibObject("plibid", "oid"); 
new PLibEntry("entryid", 0, pLibObject, new Date(1), null, SharingStatus.UNSHARED, 
        Arrays.asList("tagA", "tagB")); // entry is set in object via constructor 

Map<String, String> map = new HashMap<String, String>(); 
map.put("javax.persistence.jdbc.url", "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;LOCK_TIMEOUT=3000"); 
map.put("javax.persistence.jdbc.user", "sa"); 
map.put("javax.persistence.jdbc.password", "sa"); 
map.put(Environment.SHOW_SQL, "true"); 
map.put(Environment.FORMAT_SQL, "true"); 

EntityManagerFactory factory = Persistence.createEntityManagerFactory("plib", map); 
EntityManager entityManager = factory.createEntityManager(); 
entityManager.getTransaction().begin(); 
entityManager.persist(pLibObject); 
entityManager.getTransaction().commit(); 
+0

你能提供'SharingStatus'實施? @Entity類中的「...」是否只有getter/settes? – Xeon

+0

現在添加SharingStatus。其他方法是setter/getters和plibid(在PlibObject中)和entryid(在PLibEntry中)上的equals/hashcode。 – problemzebra

+0

請提供保存並拋出此異常的代碼 - 它可能與「持久代碼」錯誤 – Xeon

回答

1

你如何存儲數據?

也許您正在爲您的PLibObject設置一組pLibEntries,並且該集合中的每個元素PLibEntry都有一個空PLibObject,並且因爲您標記了CascadeType.ALL它試圖將PLibObject保留爲NULL Pk。

+0

我想要存儲的對象:PLibObject [id = 0,plibId = plibid,oid = oid,pLibEntries = [PLibEntry [id = 0,entryId = entryid]]](輸出toString()方法)每個PLibEntry都有一個引用到PLibObject。我使用Eclipse調試器來檢查這一點。 – problemzebra

1

看起來它認爲你正試圖給plib列的plibEntry所有權在另一個表中。嘗試指定表爲它

@ManyToOne(optional = false, cascade = CascadeType.ALL) 
    @JoinColumn(table = "pla_entries", name = "plibid") 
    private PLibObject pLibObject; 
+0

這將導致以下異常:org.hibernate.AnnotationException:無法找到預期的輔助表:沒有pla_entries可供xxxx.PLibEntry \t在org.hibernate.cfg.Ejb3Column.getJoin(Ejb3Column.java:363) \t在組織.hibernate.cfg.Ejb3Column.getTable(Ejb3Column.java:342) – problemzebra

+0

是的,有道理,你可以嘗試改變其中一個表中列的名稱嗎? – Affe

+0

將其中一個表中的plibid更改爲plibidx會導致相同的異常。 – problemzebra

1

這很奇怪 - 我使用Spring和第一插入正常工作:

PLibObject pLibObject = new PLibObject("plibid", "oid"); 
    PLibEntry entry = new PLibEntry("entryid", 0, pLibObject, new Date(1), null, SharingStatus.UNSHARED, 
      Arrays.asList("tagA", "tagB")); 
    pLibObject.getPLibEntries().add(entry); 

    SpringUtil.getBean(PLibDao.class).saveOrUpdate(pLibObject); 

PLibEntry構造:

public class PLibEntry { 

public PLibEntry(String entryId, int i, PLibObject pLibObject2, Date date, String object, 
     SharingStatus unshared, List<String> asList) { 
    this.entryId = entryId; 
    userId = i; 
    pLibObject = pLibObject2; 
    this.creationDate = date; 
    sharedFrom = ""; 
    sharingStatus = unshared; 
    tags = new HashSet<String>(asList); 
} 

Spring配置:

@Configuration 
@EnableTransactionManagement 

public class TestConfiguration { 

@Bean 
public LocalSessionFactoryBean getSessionFactory() { 
    LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean(); 
    sessionFactory.setDataSource(dataSource()); 
    sessionFactory.setPackagesToScan(new String[] { "my.package.domain" }); 
    sessionFactory.setHibernateProperties(hibernateProperties()); 
    return sessionFactory; 
} 

@Bean 
public Properties hibernateProperties() { 
    Properties properties = new Properties(); 
    properties.put("hibernate.connection.driver_class", "org.h2.Driver"); 
    properties.put("hibernate.connection.url", "jdbc:h2:db/test;CIPHER=AES"); 
    properties.put("hibernate.connection.username", "root"); 
    properties.put("hibernate.connection.password", "root root"); 
    properties.put("hibernate.connection.pool_size", "1"); 
    properties.put("hibernate.dialect", "org.hibernate.dialect.H2Dialect"); 
    properties.put("hibernate.format_sql", "true"); 
    properties.put("hibernate.use_sql_comments", "true"); 
    properties.put("hibernate.show_sql", "false"); 
    properties.put("hibernate.hbm2ddl.auto", "update"); 
    properties.put("hibernate.c3p0.min_size", "5"); 
    properties.put("hibernate.c3p0.max_size", "20"); 
    properties.put("hibernate.c3p0.timeout", "300"); 
    properties.put("hibernate.c3p0.max_statements", "50"); 
    properties.put("hibernate.c3p0.idle_test_period", "3000"); 

    properties.put("hibernate.cache.use_second_level_cache", "true"); 
    properties.put("hibernate.cache.region.factory_class", 
      "org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory"); 
    properties.put("hibernate.cache.use_query_cache", "true"); 
    properties.put("hibernate.cache.use_minimal_puts", "true"); 
    properties.put("hibernate.max_fetch_depth", "10"); 
    return properties; 
} 

@Bean 
public DataSource dataSource() { 
    DriverManagerDataSource dataSource = new DriverManagerDataSource(); 
    dataSource.setDriverClassName("org.h2.Driver"); 
    dataSource.setUrl("jdbc:h2:db/test;CIPHER=AES"); 
    dataSource.setUsername("root"); 
    dataSource.setPassword("root root"); 
    return dataSource; 
} 

@Bean 
public HibernateTransactionManager transactionManager() { 
    HibernateTransactionManager txManager = new HibernateTransactionManager(); 
    txManager.setSessionFactory(getSessionFactory().getObject()); 
    return txManager; 
} 

@Bean 
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() { 
    return new PersistenceExceptionTranslationPostProcessor(); 
} 

@Bean 
public PLibDao pLibDao() { 
    return new PLibDao(); 
} 

}

main

public class App { 
public static void main(String[] args) throws IOException { 

    PLibObject pLibObject = new PLibObject("plibid", "oid"); 
    PLibEntry entry = new PLibEntry("entryid", 0, pLibObject, new Date(1), null, SharingStatus.UNSHARED, 
      Arrays.asList("tagA", "tagB")); 
    pLibObject.getPLibEntries().add(entry); 

    SpringUtil.getBean(PLibDao.class).saveOrUpdate(pLibObject); 

SpringUtil類:

public class SpringUtil { 
private static AnnotationConfigApplicationContext ctx = buildContext(); 

private static AnnotationConfigApplicationContext buildContext() { 
    return new AnnotationConfigApplicationContext(JCashConfiguration.class); 
} 

public static AnnotationConfigApplicationContext getCtx() { 
    return ctx; 
} 

public static <T> T getBean(Class<T> classType) { 
    return ctx.getBean(classType); 
} 

public static <T> T getBean(String beanName) { 
    return (T) getBean(beanName); 
} 

}

+0

奇怪的是,當我從數據庫表中刪除外鍵約束時,對象被添加到數據庫中,但是我的單元測試失敗,因爲在pla_entries中,列plibid的值爲「1」(一個字符串)而不是「plibid」 。所以我猜,我的問題可能與使用OneToMany/ManyToOne關係的商業密鑰有關。 – problemzebra