Hibernate table doesn't exist - database
When I test my project, just 4 tables are created in the database but not the others and I do not know why. The tables notification, position, dernierePosition and user are created but not the table demande and other tables that I didn't put in this example. There are some properties that i forgot?
Thanks for your help.
Here are some files:
hibernate.cfg.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory name="">
<!-- Database connection settings, Connect to HSQL, IN Memory -->
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/***</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.connection.username">***</property>
<property name="hibernate.connection.password"/>
<!-- DB schema will be updated if needed -->
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- JDBC connection pool (use the built-in)
List of XML mapping files -->
<mapping class="modele.Demande" resource="Demande.hbm.xml"/>
<mapping class="modele.DernierePosition" resource="DernierePosition.hbm.xml"/>
<mapping class="modele.Group" resource="Group.hbm.xml"/>
<mapping class="modele.Invitation" resource="Invitation.hbm.xml"/>
<mapping class="modele.Marqueur" resource="Marqueur.hbm.xml"/>
<mapping class="modele.Notification" resource="Notification.hbm.xml"/>
<mapping class="modele.NotificationMarqueur" resource="NotificationMarqueur.hbm.xml"/>
<mapping class="modele.Position" resource="Position.hbm.xml"/>
<mapping class="modele.User" resource="User.hbm.xml"/>
</session-factory>
</hibernate-configuration>
Position.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 15 févr. 2014 01:46:28 by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping>
<class name="modele.Position" table="POSITION">
<id name="id" type="int">
<column name="ID" />
<generator class="native" />
</id>
<property name="lattitude" type="double">
<column name="LATTITUDE" />
</property>
<property name="longitude" type="double">
<column name="LONGITUDE" />
</property>
</class>
</hibernate-mapping>
DenierePosition.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 15 févr. 2014 01:46:28 by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping>
<joined-subclass name="modele.DernierePosition" extends="modele.Position" table="DERNIEREPOSITION" lazy="false">
<key>
<column name="ID" />
</key>
<property name="time" type="java.util.Date">
<column name="TIME" />
</property>
<one-to-one name="user" class="modele.User"></one-to-one>
</joined-subclass>
</hibernate-mapping>
Notification.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 15 févr. 2014 01:46:28 by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping>
<class name="modele.Notification" table="NOTIFICATION">
<id name="id" type="int">
<column name="ID" />
<generator class="native" />
</id>
<many-to-one name="user" class="modele.User" fetch="join">
<column name="USER" />
</many-to-one>
</class>
</hibernate-mapping>
Demande.java
#XmlRootElement
public class Demande extends Notification {
private Group group;
private User demandeur;
public Demande(){
}
public Demande(Group group, User demandeur) {
super(group.getProprietaire());
this.group = group;
this.demandeur=demandeur;
}
// Getters and setters
}
Demande.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 15 févr. 2014 01:46:28 by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping>
<joined-subclass name="modele.Demande" extends="modele.Notification" table="DEMANDE" lazy="false">
<key>
<column name="ID" />
</key>
<many-to-one name="group" class="modele.Group" fetch="join">
<column name="GROUP" />
</many-to-one>
<many-to-one name="demandeur" class="modele.User" fetch="join">
<column name="DEMANDEUR" />
</many-to-one>
</joined-subclass>
</hibernate-mapping>
User.java
#XmlRootElement
public class User {
/** Attributs */
private int id;
private String pseudo;
private String telephone;
private String email;
#XmlTransient
private Set<Demande> demandes;
#XmlTransient
private Set<Invitation> aInvite;
#XmlTransient
private Set<Notification> notifications;
private DernierePosition dernierePosition;
#XmlTransient
private Set<Group> groups;
#XmlTransient
private Set<Group> proprietaire;
/** Constructeur */
public User() {
}
public User(String telephone, String pseudo, String email) {
super();
this.pseudo = pseudo;
this.telephone = telephone;
this.email = email;
}
// Getters and setters
}
User.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 15 févr. 2014 01:46:28 by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping>
<class name="modele.User" table="USER">
<id name="id" type="int">
<column name="ID" />
<generator class="native" />
</id>
<property name="pseudo" type="java.lang.String">
<column name="PSEUDO" />
</property>
<property name="telephone" type="java.lang.String" not-null="true" unique="true">
<column name="TELEPHONE" />
</property>
<property name="email" type="java.lang.String">
<column name="EMAIL" />
</property>
<set name="demandes" table="DEMANDE" inverse="false" lazy="true">
<key>
<column name="ID" />
</key>
<one-to-many class="modele.Demande" />
</set>
<set name="aInvite" table="INVITATION" inverse="false" lazy="true" access="field">
<key>
<column name="ID" />
</key>
<one-to-many class="modele.Invitation" />
</set>
<set name="notifications" table="NOTIFICATION" inverse="false" lazy="true">
<key>
<column name="ID" />
</key>
<one-to-many class="modele.Notification" />
</set>
<one-to-one name="dernierePosition" class="modele.DernierePosition"></one-to-one>
<set name="groups" table="GROUP" inverse="false" lazy="true">
<key>
<column name="ID" />
</key>
<one-to-many class="modele.Group" />
</set>
<set name="proprietaire" table="GROUP" inverse="false" lazy="true">
<key>
<column name="ID" />
</key>
<one-to-many class="modele.Group" />
</set>
</class>
</hibernate-mapping>
Group.java
#XmlRootElement
public class Group {
/** Attributs */
private int id;
private String description;
private String hashtag;
private String password;
private Set<Marqueur> marqueurs;
#XmlTransient
private Set<Invitation> invitations;
#XmlTransient
private Set<Demande> demandes;
private User proprietaire;
private Set<User> invites;
/**
* Constructeur
* */
public Group()
{
}
public Group(String description, String hashtag, User proprietaire, String password) {
super();
this.description = description;
this.hashtag = hashtag;
this.proprietaire = proprietaire;
this.setPassword(password);
}
Group.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 16 f?vr. 2014 11:30:30 by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping>
<class name="modele.Group" table="GROUP">
<id name="id" type="int">
<column name="ID" />
<generator class="assigned" />
</id>
<property name="description" type="java.lang.String">
<column name="DESCRIPTION" />
</property>
<property name="hashtag" type="java.lang.String">
<column name="HASHTAG" />
</property>
<property name="password" type="java.lang.String">
<column name="PASSWORD" />
</property>
<set name="marqueurs" table="MARQUEUR" inverse="false" lazy="true">
<key>
<column name="ID" />
</key>
<one-to-many class="modele.Marqueur" />
</set>
<set name="invitations" table="INVITATION" inverse="false" lazy="true">
<key>
<column name="ID" />
</key>
<one-to-many class="modele.Invitation" />
</set>
<many-to-one name="proprietaire" class="modele.User" fetch="join">
<column name="PROPRIETAIRE" />
</many-to-one>
<set name="invites" table="USER" inverse="false" lazy="true">
<key>
<column name="ID" />
</key>
<one-to-many class="modele.User" />
</set>
</class>
</hibernate-mapping>
Test User
package dao;
import java.util.List;
import junit.framework.Assert;
import modele.User;
import org.junit.Test;
public class UserDaoTest {
private final String tel = "0601020304";
private final String pseudo = "pseudo";
private final String pseudoModified = "pseudo2";
private final String email = "email#email.com";
#Test
public void addUserTest(){
User initialUser = new User(tel, pseudo, email);
UserDao.addUser(initialUser);
User addedUser = UserDao.getUser(tel);
Assert.assertEquals(addedUser.getTelephone(), initialUser.getTelephone());
Assert.assertEquals(addedUser.getPseudo(), initialUser.getPseudo());
Assert.assertEquals(addedUser.getEmail(), initialUser.getEmail());
}
#Test
public void modifyUserTest(){
UserDao.modifyUser(tel, pseudoModified, email);
User modifiedUser = UserDao.getUser(tel);
Assert.assertEquals(modifiedUser.getTelephone(), tel);
Assert.assertEquals(modifiedUser.getPseudo(), pseudoModified);
Assert.assertEquals(modifiedUser.getEmail(), email);
}
#Test
public void listUserTest(){
User modifiedUser = UserDao.getUser(tel);
List<User> listUsers = UserDao.listUser();
User listedUser = listUsers.get(listUsers.indexOf(modifiedUser));
Assert.assertEquals(listedUser.getTelephone(), modifiedUser.getTelephone());
Assert.assertEquals(listedUser.getPseudo(), modifiedUser.getPseudo());
Assert.assertEquals(listedUser.getEmail(), modifiedUser.getEmail());
}
#Test
public void deleteUserTest(){
User user = UserDao.getUser(tel);
UserDao.deleteUser(user.getTelephone());
List<User> listUsers = UserDao.listUser();
Assert.assertEquals(listUsers.indexOf(user), -1);
}
}
It seems that there's a problem with many-to-one and joined-subclass. It's explained in detail over on the hibernate forums; I'm not entirely clear on why it's the case, but the explanation from sdknott (on that site) is:
The problem you have is with your mapping. By stating that your constraining column of the many-to-one is in fact your primary key column of table A, Hibernate will always try and resolve an entity B since the many-to-one column will never be empty.
I've used your source and changed the various many-to-one mappings in joined-subclasses to one-to-one mappings, and it all works for me now. Hopefully that will allow you to express your schema correctly.
(Aside) Original answer that didn't solve the problem
I see that you have two members called "user" in the Demande class; remember that Demande is a subclass of Notification and gets its members. I've never tried that and it looks odd, and it's definitely going to be confusing. It might be what's causing your problem.
If you really want two "user" members, give them more suitable names (maybe "requester" and "responder"? Just guessing from the context). If you only want one "user", then you don't need to put it in Demande, it's already in Notification.
Related
Is there any Solution to download attachment from gmail in WSO2 ESB / WSO2 EI?
I am working on wso2 esb since last 6 months. I want to download attachment from gmail in wso2 esb/ei and save them into local folder.Google it and get solution only for sending attachment using gmail connector, not downloading attachment. Note: Already seen,but can't able to get solution by referring the following link- WSO2 esb get attach files from email Code: ProxyService <proxy name="GmailConfigAttachment-TaskProxy" startOnLoad="true" transports="http https" xmlns="http://ws.apache.org/ns/synapse"> <target> <inSequence> <log level="custom"> <property name="Log Text" value="Inside GmailConfigAttachment-TaskProxy Service"></property> </log> <property name="FORCE_SC_ACCEPTED" scope="axis2" type="STRING" value="true" /> <property description="serviceName" name="serviceName" scope="operation" type="STRING" value="TaskScheduler_ASG_Read_Email_Body_Dummy_Service" /> <property description="messageId" expression="get-property('MessageID')" name="messageId" scope="operation" type="STRING" /> <sequence key="Load_Gmail_Configuration" /> <gmail.init> <userId>{$ctx:userId}</userId> <accessToken>{$ctx:accessToken}</accessToken> <apiUrl>{$ctx:apiUrl}</apiUrl> <clientId>{$ctx:clientId}</clientId> <clientSecret>{$ctx:clientSecret}</clientSecret> <refreshToken>{$ctx:refreshToken}</refreshToken> <accessTokenRegistryPath>{$ctx:registryPath}</accessTokenRegistryPath> </gmail.init> <gmail.listAllMails> <labelIds>INBOX</labelIds> <q>is:unread</q> </gmail.listAllMails> <log level="full" /> <iterate description="MailIterator" expression="//jsonObject/messages" sequential="true" id="listUnread"> <target> <sequence> <log description="Iterate Logger" level="custom" separator=",**, "> <property expression="fn:concat('GmailConfigAttachment-TaskProxy_Service ESB-MessageId:',get-property('operation','messageId'))" name="LogText" /> <property expression="//id/text()" name="Gmail-MessageId" /> </log> <property description="emailMsgId" expression="//id/text()" name="emailMsgId" scope="default" type="STRING" /> <property description="emailSubject" expression="//headers/name[text()='Subject']/../value/text()" name="emailSubject" scope="default" type="STRING"/> <property description="emailDate" expression="//headers/name[text()='Date']/../value/text()" name="emailDate" scope="operation" type="STRING"/> <property description="toAddress" expression="//headers/name[text()='To']/../value/text()" name="toAddress" scope="operation" type="STRING"/> <header expression="fn:concat('Bearer ', $ctx:uri.var.gmail.accessToken)" name="Authorization" scope="transport" /> <gmail.readMail> <id>{$ctx:emailMsgId}</id> </gmail.readMail> <payloadFactory media-type="xml"> <format> <htmlProcessEmailBody xmlns=""> <emailMessageId>$1</emailMessageId> <emailSubject>$2</emailSubject> <emailBody>$3</emailBody> </htmlProcessEmailBody> </format> <args> <arg evaluator="xml" expression="get-property('emailMsgId')"/> <arg evaluator="xml" expression="get-property('emailSubject')"/> <arg evaluator="xml" expression="//payload"/> </args> </payloadFactory> <log level="custom"> <property description="emailMsgId" expression="get-property('emailMsgId')" name="emailMsgId" scope="default" type="STRING" /> <property description="emailSubject" expression="//headers/name[text()='Subject']/../value/text()" name="emailSubject" scope="default" type="STRING"/> <property description="emailDate" expression="//headers/name[text()='Date']/../value/text()" name="emailDate" scope="default" type="STRING"/> <property description="toAddress" expression="//headers/name[text()='To']/../value/text()" name="toAddress" scope="default" type="STRING"/> </log> <!-- here i need further process to download attachment from gmail --> </sequence> </target> </iterate> </inSequence> <outSequence /> <faultSequence /> </target> Output of ESB So Can anyone help me to provide solution? Awaiting for your response. Thank you.
Finally i found the solution for my question. Idea : Iterating each parts then getting email attachment id which will be passed to gmail api in order to get base64 encoded format. Code snippet: <iterate continueParent="true" description="MailIterator" expression="//parts" id="listUnread" sequential="true"> <target> <sequence> <property expression="//filename[text()!=' ']" name="AttachedFileName" scope="default" type="STRING"/> <property expression="substring-after(get-property('AttachedFileName'),'.')" name="Attachmentextension" scope="default" type="STRING"/> <filter description="check emailSubject" regex="jpg|jpeg|png|gif|webp|tiff|tif|psd|raw|bmp|dib|heif|heic|indd|ind|jp2" source="lower-case(get-property('Attachmentextension'))"> <then> <property description="emailAttachmentId" expression="//attachmentId/text()" name="uri.var.attachmentId" scope="default" type="STRING"/> <log level="custom"> <property expression="get-property('AttachedFileName')" name="=====ValidAttachmentFileName===="/> <property expression="get-property('uri.var.attachmentId')" name="====emailAttachmentId====="/> </log> <header expression="fn:concat('Bearer ', $ctx:uri.var.gmail.accessToken)" name="Authorization" scope="transport"/> <call> <endpoint> <http method="get" uri-template="{+uri.var.gmail.apiUrl}/{+uri.var.gmail.apiVersion}/users/{+uri.var.gmail.userId}/messages/{+uri.var.id}/attachments/{+uri.var.attachmentId}"/> </endpoint> </call> <property description="emailAttachment" expression="//data/text()" name="emailAttachment" scope="default" type="STRING"/> <!-- ==========Script for Base64 url to Base64 Encoding Format ========== --> <script language="js"><![CDATA[var log=mc.getServiceLog(); var emailAttachment = mc.getProperty('emailAttachment'); emailAttachment=emailAttachment.replaceAll("_","/").replaceAll("-","+"); mc.setProperty("modifiedemailAttachment",emailAttachment)]]></script> <log level="custom"> <property expression="get-property('modifiedemailAttachment')" name="========modifiedemailAttachment========"/> </log>
Bind xml file to datagrid in silverlight
I am working on silverlight to bind a xml file to datagrid.I have found many example but my xml file is very complex. so how to read or bind it to data grid. Below is my xml file and i want to read element "EntityType" with its sub element and its attribute values. Thanks. `<?xml version="1.0" encoding="utf-8" ?> <edmx:Edmx Version="1.0" xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx"> <edmx:DataServices xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" m:DataServiceVersion="1.0"> <Schema Namespace="Microsoft.Crm.Sdk.Data.Services" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://schemas.microsoft.com/ado/2007/05/edm"> <EntityType Name="SdkMessageRequestField"> <Key> <PropertyRef Name="SdkMessageRequestFieldId" /> </Key> <Property Name="FieldMask" Type="Edm.Int32" Nullable="true" /> <Property Name="Name" Type="Edm.String" Nullable="true" /> </EntityType> <ComplexType Name="EntityReference"> <Property Name="Id" Type="Edm.Guid" Nullable="true" /> <Property Name="LogicalName" Type="Edm.String" Nullable="true" /> <Property Name="Name" Type="Edm.String" Nullable="true" /> </ComplexType> </Schema> </edmx:DataServices> </edmx:Edmx>`
XDocument x = XDocument.Load("XMLFileName.xml"); var a = (from c in x.Descendants("edmx").Elements("Schema").Elements("EntityType/ComplexType") select new { Name = c.Parent.Attribute("Name"), PropertyName = c.Attribute("Name"), PropertyType = c.Attribute("Type") }).ToArray(); foreach (var itm in a) { // TODO:..... }
Hibernate mapping and merging
I have 2 classes like this : Message(id, title, content) MessageEmployee(id, messageId, employeeId, readFlag) and 2 tables like this : MESSAGE(mess_id, mess_title, mess_content) MESSAGE_EMPLOYEE(mess_empl_id, mess_id, empl_id, read_fg) Mapping files : <hibernate-mapping package="core"> <class name="Message" table="MESSAGE"> <!-- class id --> <id name="id" type="int" column="MESS_ID" length="11"> <generator class="native"/> </id> <property name="content" type="string" column="MESS_CONTENT" /> <property name="title" type="string" column="MESS_TITLE" /> </class> </hibernate-mapping> <hibernate-mapping package="core"> <class name="MessageEmployee" table="MESSAGE_EMPLOYEE"> <!-- class id --> <id name="id" type="int" column="MESS_EMPL_ID" length="11"> <generator class="native"/> </id> <!-- employee --> <many-to-one name="employee" class="core.Employee" column="EMPL_ID" cascade="save-update,merge" lazy="false" /> <!-- message --> <many-to-one name="message" class="core.Message" column="MESS_ID" cascade="save-update,merge" lazy="false" /> <property name="readFlag" type="character" column="READ_FG" /> </class> </hibernate-mapping> Here is my problem : let's say I already have a message in database, and I want to create a messageEmployee and save it. Code snippet : Message sent = new Message(content, title); Employee e = employeeDao.loadEmployeeWithId(Integer.valueOf(to)); messageDao.merge(sent) MessageEmployee m = new MessageEmployee(sent, e, null); m.setReadFlag('N'); messageEmployeeDao.mergeMessageEmploye(m); When I merge(messageEmployee), it creates a new message and a new messageEmployee in database, but I don't want it to create a new message. I'm quite sure my mapping is wrong since I am no expert, so what could I change to get the behaviour I want ?
It will create a new Message object because you are not providing id in your message object sent. When you execute messageDao.merge(sent), the sent object doesn't have and id to merge with. It is pure transient object. Try loading it from database like Employee.
NHibernate and sql timestamp columns as version
I've been racking my head trying to get Nhibernate to work with a byte array as version mapping to an sql timestamp. I'd implemented an IUserVersionType but Nhibernate was creating varbinary in the database rather than timestamp. Inspired by a blog post by Ayende recently on concurrency, I changed my mapping to specify the sql-type to timestamp which worked perfectly. However I now face a rather curious problem wherein Nhibernate does an insert, gets the new version and then immediately tries to do an update and attempts to set the version column, which being an sql timestamp fails. This is my mapping: <?xml version="1.0" encoding="utf-8"?> <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Core.Domain, Version=0.1.3397.31993, Culture=neutral, PublicKeyToken=94dc7dc697cfcfc0" namespace="Core.Domain.Entities" default-lazy="false"> <class name="Contact" table="Contacts" xmlns="urn:nhibernate- mapping-2.2" optimistic-lock="version" dynamic-insert="true" dynamic- update="true"> <id name="Id" type="Int32" column="Id"> <generator class="identity" /> </id> <version name="Version" type="BinaryBlob" generated="always" unsaved-value="null"> <column name="Version" sql-type="timestamp" not-null="false" /> </version> <property name="Title" type="String"> <column name="Title" length="5" /> </property> <property name="FirstName" type="String"> <column name="FirstName" not-null="true" length="50" /> </property> <property name="MiddleName" type="String"> <column name="MiddleName" length="50" /> </property> <property name="LastName" type="String"> <column name="LastName" not-null="true" length="50" /> </property> <property name="Suffix" type="String"> <column name="Suffix" length="5" /> </property> <property name="Email" type="String"> <column name="Email" length="50" /> </property> <bag name="PhoneNumbers" inverse="true" cascade="all-delete- orphan"> <key foreign-key="FK_Contacts_PhoneNumbers_ContactId" on- delete="cascade" column="ContactId" /> <one-to-many class="Core.Domain.Entities.PhoneNumber, Core.Domain, Version=0.1.3397.31993, Culture=neutral, PublicKeyToken=94dc7dc697cfcfc0" /> </bag> <property name="DateCreated" type="DateTime"> <column name="DateCreated" /> </property> <property name="DateModified" type="DateTime"> <column name="DateModified" /> </property> <property name="LastModifiedBy" type="String"> <column name="LastModifiedBy" /> </property> </class> </hibernate-mapping> <?xml version="1.0" encoding="utf-8"?> <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Core.Domain, Version=0.1.3397.31993, Culture=neutral, PublicKeyToken=94dc7dc697cfcfc0" namespace="Core.Domain.Entities" default-lazy="false"> <class name="Customer" table="Customers" xmlns="urn:nhibernate- mapping-2.2" optimistic-lock="version" dynamic-insert="true" dynamic- update="true"> <id name="Id" type="Int32" column="Id"> <generator class="identity" /> </id> <version name="Version" type="BinaryBlob" generated="always" unsaved-value="null"> <column name="Version" sql-type="timestamp" not-null="false" /> </version> <property name="AccountNumber" access="nosetter.pascalcase- underscore" type="String"> <column name="AccountNumber" unique="true" length="25" /> </property> <!-- other mappings... --> <property name="DateCreated" type="DateTime"> <column name="DateCreated" /> </property> <property name="DateModified" type="DateTime"> <column name="DateModified" /> </property> <property name="LastModifiedBy" type="String"> <column name="LastModifiedBy" /> </property> <joined-subclass name="Core.Domain.Entities.Individual, Core.Domain, Version=0.1.3397.31993, Culture=neutral, PublicKeyToken=94dc7dc697cfcfc0" table="Individuals"> <key column="CustomerId" /> <many-to-one fetch="join" lazy="false" not-null="true" cascade="all" unique="true" not-found="exception" name="Contact" column="ContactID" /> <bag name="Addresses" table="Addresses_Individuals"> <key column="AddressId" foreign- key="FK_Addresses_Individuals_Addresses_AddressId" /> <many-to-many column="IndividualId" class="Core.Domain.Entities.Address, Core.Domain, Version=0.1.3397.31993, Culture=neutral, PublicKeyToken=94dc7dc697cfcfc0" foreign- key="FK_Addresses_Individuals_Individuals_IndividualId" /> </bag> </joined-subclass> <joined-subclass name="Core.Domain.Entities.Store, Core.Domain, Version=0.1.3397.31993, Culture=neutral, PublicKeyToken=94dc7dc697cfcfc0" table="Stores"> <key column="CustomerId" /> <many-to-one unique="true" cascade="save-update" fetch="join" not-null="true" not-found="exception" name="Address" column="AddressId" /> <many-to-one lazy="proxy" not-null="true" cascade="all" not- found="exception" name="Client" column="ClientId" /> <property name="StoreName" type="String"> <column name="StoreName" not-null="true" length="50" /> </property> <bag name="Contacts" table="Contacts_Stores"> <key column="ContactId" foreign- key="FK_Contacts_Stores_Contacts_ContactId" /> <many-to-many column="StoreId" class="Core.Domain.Entities.Contact, Core.Domain, Version=0.1.3397.31993, Culture=neutral, PublicKeyToken=94dc7dc697cfcfc0" foreign- key="FK_Contacts_Stores_Stores_StoreId" /> </bag> </joined-subclass> </class> </hibernate-mapping> Calling Session.Save on an Individual with associated Contact results in the following error: NHibernate: INSERT INTO Addresses (Line1, PostalCode, Country, DateCreated, DateModified, LastModifiedBy) VALUES (#p0, #p1, #p2, #p3, #p4, #p5); select SCOPE_IDENTITY(); #p0 = 'Order Address Line 1', #p1 = 'CV31 6BW', #p2 = 'United Kingdom', #p3 = '20/04/2009 19:45:32', #p4 = '20/04/2009 19:45:32', #p5 = '' NHibernate: SELECT address_.Version as Version22_ FROM Addresses address_ WHERE address_.Id=#p0; #p0 = '1' NHibernate: INSERT INTO Contacts (FirstName, LastName, DateCreated, DateModified, LastModifiedBy) VALUES (#p0, #p1, #p2, #p3, #p4); select SCOPE_IDENTITY(); #p0 = 'Joe', #p1 = 'Bloggs', #p2 = '20/04/2009 19:45:34', #p3 = '20/04/2009 19:45:34', #p4 = '' NHibernate: SELECT contact_.Version as Version33_ FROM Contacts contact_ WHERE contact_.Id=#p0; #p0 = '1' NHibernate: INSERT INTO Customers (AccountNumber, DateCreated, DateModified, LastModifiedBy) VALUES (#p0, #p1, #p2, #p3); select SCOPE_IDENTITY(); #p0 = '', #p1 = '20/04/2009 19:45:34', #p2 = '20/04/2009 19:45:34', #p3 = '' NHibernate: INSERT INTO Individuals (ContactID, CustomerId) VALUES (#p0, #p1); #p0 = '1', #p1 = '1' NHibernate: SELECT individual_1_.Version as Version2_ FROM Individuals individual_ inner join Customers individual_1_ on individual_.CustomerId=individual_1_.Id WHERE individual_.CustomerId=#p0; #p0 = '1' NHibernate: UPDATE Contacts SET Version = #p0 WHERE Id = #p1 AND Version = #p2; #p0 = 'System.Byte[]', #p1 = '1', #p2 = 'System.Byte[]' System.Data.SqlClient.SqlException: Cannot update a timestamp column. at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection) at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection) at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning (TdsParserStateObject stateObj) at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj) at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString) at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds (CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result) at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery (DbAsyncResult result, String methodName, Boolean sendToPipe) at System.Data.SqlClient.SqlCommand.ExecuteNonQuery() at NHibernate.AdoNet.AbstractBatcher.ExecuteNonQuery(IDbCommand cmd) in c:\CSharp\NH\nhibernate\src\NHibernate\AdoNet\AbstractBatcher.cs: line 203 at NHibernate.Persister.Entity.AbstractEntityPersister.Update(Object id, Object[] fields, Object[] oldFields, Object rowId, Boolean[] includeProperty, Int32 j, Object oldVersion, Object obj, SqlCommandInfo sql, ISessionImplementor session) in c:\CSharp\NH \nhibernate\src\NHibernate\Persister\Entity \AbstractEntityPersister.cs: line 2713 NHibernate.Exceptions.GenericADOException: could not update: [Core.Domain.Entities.Contact#1][SQL: UPDATE Contacts SET Version = #p0 WHERE Id = #p1 AND Version = #p2] Any ideas why NHibernate is attempting to update the version column for Contact, even though it didn't for the Address?
I have found that using dynamic-insert="true" on the class along with causes this issue. I use the following mapping successfully: ... <class name="Contact" table="Contact"> <id name="ID" column="ID" type="int"> <generator class="identity" /> </id> <version name="Version" generated="always" unsaved-value="null" type="BinaryBlob"/> ...
The Address doesn't have a version column I assume. I wonder where you have the sql-type from. Why not this way? <version name="Version" type="Timestamp" generated="always" unsaved-value="null"> <column name="Version" not-null="false" /> </version> You need of course a DateTime in the entity.
http://ayende.com/Blog/archive/2009/04/15/nhibernate-mapping-concurrency.aspx
nHibernate Master Detail Deletion
I have a Master Detail relationship configured. The hbm file is below. When I run some code like this Favourite favourite = favourites.Find(f => f.Id== id); user.Favourites.Remove(favourite); m_UserRepository.Save(ref user); I get the error message NHibernate.Exceptions.GenericADOException: could not delete collection rows: [Model.Entities.User.Favourites#249][SQL: SQL not available] ---> System.Data.SqlClient.SqlException: Cannot insert the value NULL into column 'UserId', table 'BE.Favourite'; column does not allow nulls. UPDATE fails. Any suggestions on what this means please help. <?xml version="1.0" encoding="utf-8" ?> <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="Model.Entities" schema="BE" assembly="Model" default-lazy="false"> <class name="Model.Entities.User, Model" table="Users" > <id name="UserId" column="UserId" type="int" unsaved-value="0"> <generator class="native" /> </id> <property name="UserName" column="UserName" type="string" /> <bag name="Favourites" cascade="all" lazy="true"> <key column="UserId"/> <one-to-many class="Model.Entities.Favourite, Model"/> </bag> </class> </hibernate-mapping>
Have you tried setting inverse="true" on your bag?
You actually need a many-to-many relationship in this case: <class name="User"> <id name="Id"> <generator class="native"> <param name="sequence">object_sequence</param> </generator> </id> <version name="Version" /> <property name="Name" /> <set name="Roles" table="User_Favourite"> <key column="UserId"/> <many-to-many column="FavouriteId" class="Favourite"/> </set> </class> And the same on the other side: (*note the inverse="true") <class name="Favourite"> <id name="Id"> <generator class="native"> <param name="sequence">object_sequence</param> </generator> </id> <version name="Version" /> <property name="RoleName" /> <set name="Users" table="User_Favourite" inverse="true"> <key column="FavouriteId"/> <many-to-many column="UserId" class="User"/> </set> </class> From the NHibernate 2.0 Documentation: Very Important Note: If the <key> column of a <one-to-many> association is declared NOT NULL, NHibernate may cause constraint violations when it creates or updates the association. To prevent this problem, you must use a bidirectional association with the many valued end (the set or bag) marked as inverse="true". See the discussion of bidirectional associations later in this chapter. Finally, I'm unsure if you really want to use a bag here. One user can have the same favorite two or more times? P.S.: Also, note that lazy="true" is the default behavior since NHibernate 1.2.
try changing your cascade rule to: <bag name="Favourites" cascade="all,delete-orphan" lazy="true"> <key column="UserId" not-null="true"/> <one-to-many class="Model.Entities.Favourite, Model"/> </bag>