Why am I getting Mapping Exception? - java

I am getting :
org.hibernate.MappingException: Foreign key (FKBB979BF4266AA123:address [a_id]))
must have same number of columns as the referenced
primary key (address [p_id,a_id])
as I try to run the following (though incomplete) snippet :
public static void main(String args[]) {
Configuration config = new Configuration().configure();
SessionFactory sessFact = config.buildSessionFactory();
Session sess = sessFact.openSession();
Transaction trans = sess.beginTransaction();
}
The hibernate mapping xml is shown below :
<class name="pojo.Person" table="person">
<id column="p_id" name="personID">
<generator class="increment" />
</id>
<property name="personName" column="p_name" />
<set name="addressSet" table="address" cascade="all">
<key column="p_id" />
<many-to-many class="pojo.Address" column="a_id" />
</set>
</class>
<class name="pojo.Address" table="address">
<id column="a_id" name="addressID">
<generator class="foreign" />
</id>
<property name="address" column="address" />
</class>
I am trying a many to many association between Person and Address class.
What is the reason for this exception ?
I have created two tables person and address using these sql commands :
CREATE TABLE person(p_id INTEGER,p_name TEXT,PRIMARY KEY(p_id));
CREATE TABLE address(a_id INTEGER,address TEXT);
POJO
Person
public class Person {
private int personID;
private String personName;
private Set addressSet;
public int getPersonID() {
return personID;
}
public void setPersonID(int personID) {
this.personID = personID;
}
public String getPersonName() {
return personName;
}
public void setPersonName(String personName) {
this.personName = personName;
}
public Set getAddressSet() {
return addressSet;
}
public void setAddressSet(Set addressSet) {
this.addressSet = addressSet;
}
Address
public class Address {
private int addressID;
private String address;
private Set personSet;
public int getAddressID() {
return addressID;
}
public void setAddressID(int addressID) {
this.addressID = addressID;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Set getPersonSet() {
return personSet;
}
public void setPersonSet(Set personSet) {
this.personSet = personSet;
}
}

For a ManyToMany Relationshhip you need a dedicated mapping table
6.2.4. Collections of values and many-to-many associations
i.e. You need something like a PersonAddress Table
CREATE TABLE personaddress (p_id integer, a_id integer)
Where p_id is a FK Reference to the Person Table and a_id a FK Reference to the Address Table

You need to specify different table name for many-to-many association as it's handled by a separate table:
<class name="pojo.Person" table="person">
<id column="p_id" name="personID">
<generator class="increment" />
</id>
<property name="personName" column="p_name" />
<set name="addressSet" table="person_address" cascade="all">
<key column="p_id" />
<many-to-many class="pojo.Address" column="a_id" />
</set>
</class>
Note that <set> now references to person_addresses table. With default configuration, Hibernate is able to create it automatically.
There's another mistake that I see: ID generator for Address entity should not be foreign, it's usually used in 1-to-1 relationships (uses ID of another associated object). You can use the same 'increment' use used for Person entity:
<class name="Address" table="address">
<id column="a_id" name="addressID">
<generator class="increment" />
</id>
<property name="address" column="address" />
</class>

You need to create a reference table:
CREATE TABLE PersonsAddresses (personId BIGINT, addressId BIGINT)
and change the mapping of the set to this:
<set name="addressSet" table="PersonsAddresses" order-by="personId">
<key column="personId" foreign-key="p_id"/>
<many-to-many column="addressId" node="a_id" class="pojo.Address" />
</set>

Related

java.lang.Object; cannot be cast to shoppingbasket.Product

I am trying to retrieve a list of products with they're associated offers. After iterating through the result of the query I want to be able to use the getters/setters from the products class but I know it's not working because the query is not returning an instance of Product.
function to grab the products:
public List<Product> getProducts() {
factory = (new Configuration()).configure().buildSessionFactory();
Session session = factory.getCurrentSession();
session.beginTransaction();
List<Product> products = new ArrayList<Product>();
Query query = session.createQuery("from Product p INNER JOIN p.offers");
//The castList is declared and explained at the bottom of listing
List<Product> list = query.list();
Iterator<Product> iter = list.iterator();
while (iter.hasNext()) {
Product product = iter.next();
System.out.println(product);
}
}
Hibernate mapping for Offer:
<hibernate-mapping>
<class name="shoppingbasket.Offer" table="offers">
<id name="offerID" type="integer" access="field">
<column name="OfferID" />
<generator class="assigned" />
</id>
<property name="offerDescription" type="java.lang.String" access="field">
<column name="OfferDescription" length="60" not-null="true"/>
</property>
<property name="shortDescription" type="java.lang.String" access="field">
<column name="ShortDescription" length="10" not-null="false"/>
</property>
<property name="TFTPOTGroup" type="java.lang.Integer" access="field">
<column name="TFTPOTGroup" length="4" not-null="false" default="null"/>
</property>
<property name="discountPercentage" type="java.lang.Double" access="field">
<column name="DiscountPercentage" not-null="false" default="null"/>
</property>
</class>
Hibernate mapping for Product:
<hibernate-mapping>
<class name="shoppingbasket.Product" table="products">
<id name="productID" type="integer" access="field">
<column name="ProductID" />
<generator class="assigned" />
</id>
<property name="offerID" type="java.lang.Integer" access="field">
<column name="OfferID" />
</property>
<property name="productName" type="java.lang.String" access="field">
<column name="ProductName" length="40" not-null="true"/>
</property>
<property name="unitPrice" type="java.math.BigDecimal" access="field">
<column name="UnitPrice"/>
</property>
<one-to-one name="offers" class="shoppingbasket.Offer" />
</class>
Product class:
public class Product implements java.io.Serializable {
private Integer productID;
private Integer offerID;
private String productName;
private BigDecimal unitPrice;
private Offer offer;
public Integer getProductID() {
return productID;
}
public void setProductID(Integer productID) {
this.productID = productID;
}
public Integer getOfferID() {
return this.offerID;
}
public void setOfferID(Integer offerID) {
this.offerID = offerID;
}
public Offer getOffers() {
return offer;
}
public void setOffers(Offer offer) {
this.offer = offer;
}
//more getters/setters
}
Offer class:
public class Offer
{
private Integer offerID;
private String offerDescription;
private String shortDescription;
private Integer TFTPOTGroup;
private Double discountPercentage;
public Integer getOfferID() {
return offerID;
}
public void setOfferID(Integer offerID) {
this.offerID = offerID;
}
//more getters/setters
}
Any help would be hugely appreciated
#Potential Unnecessary Projections Data:
Since you're not specifying SELECT clause in the query and putting explicit joins, hibernate will return 2 objects per row (Product, Offers), wherein Product object might already be populated with the Offer data due to underlying mapping associations.
Try adding select clause to the query and see if it casts correctly
Add SELECT p FROM ... to the query

How to tell Hibernate to map a one-to-many key column into derived class table?

How can I create a Hibernate mapping for a one-to-many mapping to a polymorphic class so that the foreign key is added to the child table?
The polymorphic class is mapped so that the base class has its own table and the child class has a table joined to the base class table. All my attempts add an id column and foreign key to the base table.
Java classes:
public class Base
{
private String id;
private int BaseProperty;
public String getId()
{
return id;
}
public void setId(String id)
{
this.id = id;
}
public int getBaseProperty()
{
return BaseProperty;
}
public void setBaseProperty(int baseProperty)
{
BaseProperty = baseProperty;
}
}
public class Child extends Base
{
private int childProperty;
public int getChildProperty()
{
return childProperty;
}
public void setChildProperty(int childProperty)
{
this.childProperty = childProperty;
}
}
public class Owner
{
private String id;
private Set<Child> children;
public String getId()
{
return id;
}
public void setId(String id)
{
this.id = id;
}
public Set<Child> getChildren()
{
return children;
}
public void setChildren(Set<Child> children)
{
this.children = children;
}
}
Hibernate mapping:
<hibernate-mapping auto-import="true" default-lazy="false">
<class name="net.opsource.oec.integration.service.sven.Owner"
table="SR_OWNER">
<id name="id" type="string" unsaved-value="null">
<column name="ID" sql-type="char(128)" not-null="true"/>
<generator class="assigned"/>
</id>
<set name="children" cascade="all">
<key column="OWNED_CHILD_ID" foreign-key="FK_CHILD2_OWNER"/>
<one-to-many class="net.opsource.oec.integration.service.sven.Child"/>
</set>
</class>
<class name="net.opsource.oec.integration.service.sven.Base"
abstract="true" table="SR_BASE"
discriminator-column="Base">
<discriminator column="JOB_TYPE" type="string" length="50"/>
<id name="id" type="string" unsaved-value="null">
<column name="ID" sql-type="char(128)" not-null="true"/>
<generator class="assigned"/>
</id>
<discriminator column="TYPE" type="string" length="50"/>
<property name="baseProperty"/>
</class>
<subclass name="net.opsource.oec.integration.service.sven.Child"
extends="net.opsource.oec.integration.service.sven.Base"
discriminator-value="Child">
<join table="SR_CHILD" fetch="select">
<key column="CHILD_ID" unique="true"
foreign-key="FK_CHILD_BASE"/>
<property name="childProperty"/>
</join>
</subclass>
</hibernate-mapping>
This generates the following schema:
create table SR_BASE (
ID char(128) not null,
TYPE varchar(50) not null,
baseProperty integer,
OWNED_CHILD_ID varchar(255),
primary key (ID)
) ENGINE=InnoDB;
create table SR_CHILD (
CHILD_ID varchar(255) not null,
childProperty integer,
primary key (CHILD_ID)
) ENGINE=InnoDB;
create table SR_OWNER (
ID char(128) not null,
primary key (ID)
) ENGINE=InnoDB;
How can I tell Hibernate to create the OWNED_CHILD_ID column and its key in the SR_CHILD table instead?
We are using Hibernate 4.2.
Thanks / Sven

How to structure SQL Statement to avoid so many joins

I am trying to build a select statement which will allow me to build a local in app cache when my application starts up. My table structure looks as follows;
I know to get some help I must demonstrate what I have already attempted but its extremely
I am using hibernate which should make things easier but I am really hitting a road block, the only approach I can think of is to select all the fields and then do a left outer join on the table ids matching, however the issue with this approach is that one user can have 0-1 business cards/ 0-1 social cards, 0-1 personal cards which means when i left outer join some of the data potentially might be missing for a user. The personalInfo/Logindetails and Device Data is all 1:1 mapping
Is there a more efficient way to do the select in hibernate which will allow me to easily construct my cache?
Ideally I would like to construct an object such that;
public class User {
private BusinessCard businessCard;
private SocialCard socialCard;
private PersonalCard personalCard;
private PersonalInformation personalInformation;
private LoginDetails loginDetails;
private DeviceData deviceData;
public BusinessCard getBusinessCard() {
return businessCard;
}
public void setBusinessCard(BusinessCard businessCard) {
this.businessCard = businessCard;
}
public SocialCard getSocialCard() {
return socialCard;
}
public void setSocialCard(SocialCard socialCard) {
this.socialCard = socialCard;
}
public PersonalCard getPersonalCard() {
return personalCard;
}
public void setPersonalCard(PersonalCard personalCard) {
this.personalCard = personalCard;
}
public PersonalInformation getPersonalInformation() {
return personalInformation;
}
public void setPersonalInformation(PersonalInformation personalInformation) {
this.personalInformation = personalInformation;
}
public LoginDetails getLoginDetails() {
return loginDetails;
}
public void setLoginDetails(LoginDetails loginDetails) {
this.loginDetails = loginDetails;
}
public DeviceData getDeviceData() {
return deviceData;
}
public void setDeviceData(DeviceData deviceData) {
this.deviceData = deviceData;
}
}
Thanks
From Hibernate Community Documentation - Charpter 7 - Association Mappings:
7.2.1. Many-to-one
A unidirectional many-to-one association is the most common kind of unidirectional association.
<class name="Person">
<id name="id" column="personId">
<generator class="native"/>
</id>
<many-to-one name="address"
column="addressId"
not-null="true"/>
</class>
<class name="Address">
<id name="id" column="addressId">
<generator class="native"/>
</id>
</class>
create table Person (
personId bigint not null primary key
, addressId bigint not null
)
create table Address (
addressId bigint not null primary key
)
7.2.2. One-to-one
A unidirectional one-to-one association on a foreign key is almost identical. The only difference is the column unique constraint.
<class name="Person">
<id name="id" column="personId">
<generator class="native"/>
</id>
<many-to-one name="address"
column="addressId"
unique="true"
not-null="true"/>
</class>
<class name="Address">
<id name="id" column="addressId">
<generator class="native"/>
</id>
</class>
create table Person (
personId bigint not null primary key
, addressId bigint not null unique
)
create table Address (
addressId bigint not null primary key
)
This is how you may map one-to-one relationship. Notice this is the same sa many-to-one mapping, except for the unique constraint.
Now having mapped your classes, your Person class shall look like the following.
public class Person {
public Address getAddress() { return address; }
public void setAddress(Address address) { this.address = address; }
public int getId() { return id; }
protected void setId(int id) { this.id = id; }
private Address address;
private int id;
}
To answer your question
It all depends how you want the data to be persisted. As expressed, I would go with the identities of BusinessCard, SocialCard and PersonalCard into the User table so that one and only one card may exist per user.
<class name "User" table="Users">
<id name="id" column="userId">
<generator class="native" />
</id>
<many-to-one name="businessCard"
column="businessCardId"
unique="true"
not-null="true" />
<many-to-one name="socialCard"
column="socialCardId"
unique="true"
not-null="true" />
<many-to-one name="personalCard"
column="personalCardId"
unqiue="true"
not-null="true" />
</class>
<class name="BusinessCard" table="BusinessCards">
<id name="id" column="businessCardId">
<generator class="native" />
</id>
</class>
<class name="SocialCard" table="SocialCards">
<id name="id" column="socialCardId">
<generator class="native" />
</id>
</class>
<class name="PersonalCard" table="PersonalCards">
<id name="id" column="personalCardId">
<generator class="native" />
</id>
</class>

Hibernate inverse one to many mapping does not seem to properly handle item removal from Java list

Two classes:
<class name="SpreadsheetImportTemplate" table="spreadsheetimport_template">
<id name="id" type="int" column="id" unsaved-value="0">
<generator class="native" />
</id>
<property name="name" type="java.lang.String" column="name" not-null="true" length="100" />
<many-to-one name="creator" class="org.openmrs.User" not-null="true" />
<property name="created" type="java.util.Date" column="date_created" not-null="true"
length="19" />
<many-to-one name="modifiedBy" column="changed_by" class="org.openmrs.User" not-null="false" />
<property name="modified" type="java.util.Date" column="date_changed" not-null="false" length="19" />
<!-- Associations -->
<!-- bi-directional one-to-many association to SpreadsheetImportTemplateColumn -->
<bag name="columns" cascade="all-delete-orphan" inverse="true">
<key column="template_id" not-null="true" />
<one-to-many class="SpreadsheetImportTemplateColumn" />
</bag>
</class>
<class name="SpreadsheetImportTemplateColumn" table="spreadsheetimport_template_column">
<id name="id" type="int" column="id" unsaved-value="0">
<generator class="native" />
</id>
<many-to-one name="template" class="SpreadsheetImportTemplate" column="template_id" />
<property name="columnName" type="java.lang.String" column="column_name" length="100" not-null="true" />
<property name="dbTableDotColumn" type="java.lang.String" column="db_table_dot_column" length="100" not-null="true"/>
<property name="extraData" type="java.lang.String" column="extra_data" length="100" not-null="false"/>
</class>
In java both have following with respective getters and setters:
public class SpreadsheetImportTemplate {
Integer id;
String name;
Collection<SpreadsheetImportTemplateColumn> columns = new ArrayList<SpreadsheetImportTemplateColumn>();
Date created;
Date modified;
User creator;
User modifiedBy;
public SpreadsheetImportTemplate() {
}
...
public class SpreadsheetImportTemplateColumn {
Integer id;
SpreadsheetImportTemplate template;
String columnName;
String dbTableDotColumn;
String extraData;
public SpreadsheetImportTemplateColumn() {
}
...
However, if we have a SpreadsheetImportTemplate template with some columns, and we do a template.remove(0) and then a Hibernate saveOrUpdate, the relevant SpreadsheetImportTemplateColumn does not get deleted from the database :(
Any help appreciated.
Fyi, here is the relevant SQL that creates the databases:
CREATE TABLE IF NOT EXISTS `spreadsheetimport_template` (
`id` int(32) NOT NULL auto_increment,
`name` varchar(100) NOT NULL,
`creator` int(11) NOT NULL default '0',
`date_created` datetime NOT NULL default '0000-00-00 00:00:00',
`changed_by` int(11) default NULL,
`date_changed` datetime default NULL,
PRIMARY KEY (`id`),
KEY `User who wrote this spreadsheet template` (`creator`),
KEY `User who changed this spreadsheet template` (`changed_by`),
CONSTRAINT `User who wrote this spreadsheet template` FOREIGN KEY (`creator`) REFERENCES `users` (`user_id`),
CONSTRAINT `User who changed this spreadsheet template` FOREIGN KEY (`changed_by`) REFERENCES `users` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `spreadsheetimport_template_column` (
`id` int(32) NOT NULL auto_increment,
`template_id` int(32) NOT NULL default '0',
`column_name` varchar(100) NOT NULL,
`db_table_dot_column` varchar(100) NOT NULL,
`extra_data` varchar(100),
PRIMARY KEY (`id`),
KEY `Spreadsheet template to which this column belongs` (`template_id`),
CONSTRAINT `Spreadsheet template to which this column belongs` FOREIGN KEY (`template_id`) REFERENCES `spreadsheetimport_template` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Just relevant part
SpreadsheetImportTemplate
public class SpreadsheetImportTemplate {
private Integer id;
public Integer getId() { return id; }
public void setId(Integer id) { this.id = id; }
private Collection<SpreadsheetImportTemplateColumn> columns = new ArrayList<SpreadsheetImportTemplateColumn>();
public Collection<SpreadsheetImportTemplateColumn> getColumns() { return columns; }
public void setColumns(Collection<SpreadsheetImportTemplateColumn> columns) { this.columns = columns; }
/**
* set up both sides
*/
public void addColumn(SpreadsheetImportTemplateColumn column) {
getColumns().add(column);
column.setTemplate(this);
}
}
SpreadsheetImportTemplateColumn
public class SpreadsheetImportTemplateColumn {
private Integer id;
public Integer getId() { return id; }
public void setId(Integer id) { this.id = id; }
private SpreadsheetImportTemplate template;
public SpreadsheetImportTemplate getTemplate() { return template; }
public void setTemplate(SpreadsheetImportTemplate template) { this.template = template; }
}
mapping
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="br.com._3589013.model.domain">
<class name="SpreadsheetImportTemplate">
<id name="id">
<generator class="native"/>
</id>
<bag name="columns" cascade="all,delete-orphan" inverse="true">
<key/>
<one-to-many class="SpreadsheetImportTemplateColumn"/>
</bag>
</class>
<class name="SpreadsheetImportTemplateColumn">
<id name="id">
<generator class="native"/>
</id>
<many-to-one name="template" class="SpreadsheetImportTemplate"/>
</class>
</hibernate-mapping>
Test
public class PersistenceTest {
private static SessionFactory sessionFactory;
private Serializable id;
#BeforeClass
public static void setUpClass() {
Configuration c = new Configuration();
c.addResource("mapping.hbm.3589013.xml");
sessionFactory = c.configure().buildSessionFactory();
}
#Before
public void setUp() throws Exception {
SpreadsheetImportTemplate sit = new SpreadsheetImportTemplate();
sit.addColumn(new SpreadsheetImportTemplateColumn());
Session session = sessionFactory.openSession();
session.beginTransaction();
id = session.save(sit);
session.getTransaction().commit();
}
#Test
public void removedOrphan() throws Exception {
Session session = sessionFactory.openSession();
session.beginTransaction();
List<SpreadsheetImportTemplateColumn> sitcList = session.createQuery("from SpreadsheetImportTemplateColumn").list();
assertTrue(sitcList.size() == 1);
SpreadsheetImportTemplate sit = (SpreadsheetImportTemplate) session.get(SpreadsheetImportTemplate.class, id);
sit.getColumns().remove(sitcList.get(0));
session.getTransaction().commit();
assertTrue(sit.getColumns().size() == 0);
}
}
It works fine!
I could not figure it out.
I hacked a work around:
public class SpreadsheetImportDAOImpl implements SpreadsheetImportDAO {
...
public SpreadsheetImportTemplate saveSpreadsheetImportTemplate(SpreadsheetImportTemplate template) {
// TODO: Hack - how does this get specified properly in hbm.xml files???
// Column processing: delete columns that must be deleted, make sure template field
// points to template
Iterator<SpreadsheetImportTemplateColumn> columnIterator = template.getColumns().iterator();
while (columnIterator.hasNext()) {
SpreadsheetImportTemplateColumn column = columnIterator.next();
if (column.isDeleted()) {
columnIterator.remove();
sessionFactory.getCurrentSession().delete(column);
} else {
column.setTemplate(template);
}
}
sessionFactory.getCurrentSession().saveOrUpdate(template);
return template;
}
...
}

Hibernate one-to-one mapping problem

Hello I've the following class:
public class Movimenti implements java.io.Serializable {
private Integer id = null;
private Integer idCommessa = null;
private String nomemovimento = null;
private Movimento preventivato = null;
private Movimento effettivo = null;
public Movimento getEffettivo() {
return effettivo;
}
public void setEffettivo(Movimento effettivo) {
this.effettivo = effettivo;
}
public Movimento getPreventivato() {
return preventivato;
}
public void setPreventivato(Movimento preventivato) {
this.preventivato = preventivato;
}
public Movimenti() {
}
public Movimenti(Integer idCommessa, String nomemovimento) {
this.idCommessa = idCommessa;
this.nomemovimento = nomemovimento;
}
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getIdCommessa() {
return this.idCommessa;
}
public void setIdCommessa(Integer idCommessa) {
this.idCommessa = idCommessa;
}
public String getNomemovimento() {
return this.nomemovimento;
}
public void setNomemovimento(String nomemovimento) {
this.nomemovimento = nomemovimento;
}
}
As you can see there are two Movimento references. Movimento looks like this:
public class Movimento {
Integer id = null;
Movimenti movimenti;
String descrizione = null;
public Movimenti getMovimenti() {
return movimenti;
}
public void setMovimenti(Movimenti movimenti) {
this.movimenti = movimenti;
}
public String getDescrizione() {
return descrizione;
}
public void setDescrizione(String descrizione) {
this.descrizione = descrizione;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
}
there is a reference to Movimenti in movimento. Now movimento is a base class for other classes and that gives no problems as SchemaExport does his job correctly. What I want is to have a one-to-one relationship between Movimento and Movimenti, so that I can have automatic retrivial of Movimento when I load up a Movimenti instance and vice versa and automatic deletion of orphaned Movimento objects. So I thought of putting two one-to-one relationships in Movimenti towards Movimento and one backwards. But it doesn't work, it doesn't generate the correct database tables and it even gives out exceptions. These are the mappings (there are even the subclasses that I don't include).
Movimento.hbm.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class dynamic-insert="false" dynamic-update="false" mutable="true" name="persistence.beans.jCommesse.Movimento" optimistic-lock="version" polymorphism="implicit" select-before-update="false">
<id name="id" type="java.lang.Integer">
<column name="id" />
<generator class="identity" />
</id>
<property name = "descrizione" type="java.lang.String">
<column name = "descrizione"></column>
</property>
<one-to-one name = "movimenti" class = "persistence.beans.jCommesse.Movimento" constrained="true">
</one-to-one>
<joined-subclass name = "persistence.beans.jCommesse.Materiali" table = "Materiali">
<key column="id"/>
<property name = "consegnato" type="java.lang.Boolean">
<column name = "consegnato"/>
</property>
<property name="costo" type = "java.lang.Double">
<column name = "costo"/>
</property>
<property name = "costoTrasporto" type = "java.lang.Double">
<column name = "costoTrasporto"/>
</property>
<property name = "quantita" type = "java.lang.Double">
<column name = "quantita"/>
</property>
<property name = "riferimentoFattura" type = "java.lang.Integer">
<column name = "riferimentoFattura"/>
</property>
<property name = "tipoQuantita" type = "java.lang.String">
<column name = "tipoQuantita"/>
</property>
</joined-subclass>
<joined-subclass name = "persistence.beans.jCommesse.RientroMateriali" table = "RientroMateriali">
<key column="id"/>
<property name = "costo" type = "java.lang.Double">
<column name = "costo"/>
</property>
<property name = "costoDelTrasporto" type = "java.lang.Double">
<column name = "costoDelTrasporto"/>
</property>
<property name = "quantita" type = "java.lang.Double">
<column name = "quantita"/>
</property>
<property name = "riferimentoFattura" type = "java.lang.Integer">
<column name = "riferimentoFattura"/>
</property>
<property name = "tipoQuantita" type = "java.lang.String">
<column name = "tipoQuantita"/>
</property>
</joined-subclass>
<joined-subclass name = "persistence.beans.jCommesse.CostiExtra" table = "CostiExtra">
<key column = "id"/>
<property name = "nota" type = "java.lang.String">
<column name = "nota"/>
</property>
<property name = "prezzo" type = "java.lang.Double">
<column name = "prezzo"/>
</property>
</joined-subclass>
</class>
</hibernate-mapping>
and Movimenti.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 10-feb-2010 11.24.48 by Hibernate Tools 3.2.1.GA -->
<hibernate-mapping>
<class name="persistence.beans.jCommesse.Movimenti" table="movimenti" catalog="jcommesse">
<id name="id" type="java.lang.Integer">
<column name="id" />
<generator class="identity" />
</id>
<property name="idCommessa" type="java.lang.Integer">
<column name="idCommessa" />
</property>
<property name="nomemovimento" type="string">
<column name="nomemovimento" length="250" />
</property>
<one-to-one name="preventivato" class="persistence.beans.jCommesse.Movimento" cascade="all" />
</class>
</hibernate-mapping>
all this doesn't create the tables but instead comes out with this nasty exception:
10-feb-2010 15.04.46 org.hibernate.tool.hbm2ddl.SchemaUpdate execute
INFO: schema update complete
Exception in thread "main" org.hibernate.PropertyValueException: not-null property references a null or transient value: persistence.beans.jCommesse.Materiali.movimenti
at org.hibernate.engine.Nullability.checkNullability(Nullability.java:72)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:290)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:181)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:107)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:187)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:172)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:94)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
at org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:507)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:499)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:495)
at testgeneration.testSchema(testgeneration.java:34)
at testgeneration.main(testgeneration.java:53)
Java Result: 1
as you can see it says "schema generation complete" (I'm using update for development).
Movimenti and Movimento come out like this on mySQL:
CREATE TABLE `movimenti` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`idCommessa` int(11) DEFAULT NULL,
`nomemovimento` varchar(250) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
and
CREATE TABLE `movimento` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`descrizione` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `FKBEB397FC4778E205` (`id`),
CONSTRAINT `FKBEB397FC4778E205` FOREIGN KEY (`id`) REFERENCES `movimento` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=latin1
I've found a couple of issues:
The exception is because of a bug in the use of the class Materiali (it also has a field movimenti that must be non-null but that's not related to your question and you're confused by it).
In the mapping Movimenti.hbm.xml, you forgot to map the two fields preventivato and effettivo. You must map them with reverse=true.
I really suggest to use annotations for the mapping. They are much more simple to use and keep all the information in one place.
The reason why you don't see any references in the two tables is because Hibernate creates a many-to-many mapping (which needs a third table). I understand what you're trying to achieve but I'm not sure Hibernate is smart enough to do it.

Categories

Resources