I've got a question. I use NHibernate with MySql. At my entities I use Id(PK) for my business-logic usage and Guid(for replication). So my BaseDomain:
public class BaseDomain
{
public virtual int Id { get; set; }
public virtual Guid Guid { get; set; }
public class Properties
{
public const string Id = "Id";
public const string Guid = "Guid";
}
public BaseDomain() { }
}
My usage domain:
public class ActivityCategory : BaseDomain
{
public ActivityCategory() { }
public virtual string Name { get; set; }
public new class Properties
{
public const string Id = "Id";
public const string Guid = "Guid";
public const string Name = "Name";
private Properties() { }
}
}
Mapping:
<class name="ActivityCategory, Clients.Core" table='Activity_category'>
<id name="Id" unsaved-value="0" type="int">
<column name="Id" not-null="true"/>
<generator class="native"/>
</id>
<property name="Guid"/>
<property name="Name"/>
</class>
But when I insert my entity:
[Test]
public void Test()
{
ActivityCategory ac = new ActivityCategory();
ac.Name = "Test";
using (var repo = new Repository<ActivityCategory>())
repo.Save(ac);
}
I always get '00000000-0000-0000-0000-000000000000' at my Guid field.
What should I do for generate right Guid. May be mapping?
Thanks a lot!
From a NHibernate perspective, you should either set the guid in C# or tell NHibernate that it is generated by the database.
In the former case, set the guid property in the constructor.
public class BaseDomain
{
public BaseDomain()
{
Guid = Guid.NewGuid();
}
}
You map a property whose value is generated in the database like this. Depending on how the value is generated, you may also need to exclude the property from insert statements.
<class name="ActivityCategory, Clients.Core" table="Activity_category">
<id name="Id" not-null="true" >
<generator class="native" />
</id>
<property name="Guid" generated="insert" insert="false" update="false" />
<property name="Name" />
</class>
Related
I am making a java ee web application. I have User and Permission classes and User class have List that types of Permission. When hibernate gets user object form database, i want to get permissions of user from user_permission table ,too. User and Permission has many-to-many relation. I am using Hibernate 5.4.1 . When SessionFactory configurating i get this error:
java.lang.NullPointerException
org.hibernate.boot.model.source.internal.hbm.ModelBinder$AbstractPluralAttributeSecondPass.bindCollectionElement(ModelBinder.java:3557)
org.hibernate.boot.model.source.internal.hbm.ModelBinder$AbstractPluralAttributeSecondPass.doSecondPass(ModelBinder.java:3136)
org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1684)
org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1652)
org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:286)
org.hibernate.boot.model.process.spi.MetadataBuildingProcess.build(MetadataBuildingProcess.java:83)
org.hibernate.boot.internal.MetadataBuilderImpl.build(MetadataBuilderImpl.java:473)
org.hibernate.boot.internal.MetadataBuilderImpl.build(MetadataBuilderImpl.java:84)
org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:689)
org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:724)
my User class:
public class User
{
private int id;
private String name;
private String password;
private List<Permission> permissions;
public User(){}
public User(String name,String password)
{
this.name=name;
this.password=password;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name=name;
}
public String getPassword()
{
return password;
}
public void setPassword(String password)
{
this.password=password;
}
public int getId()
{
return id;
}
public void setId(int id)
{
this.id=id;
}
public void clearPermissions()
{
permissions.clear();
}
public boolean hasPermission(Permission permission)
{
return permissions.contains(permission);
}
public void addPermission(Permission permission)
{
permissions.add(permission);
}
public void deletePermission(Permission permission)
{
permissions.remove(permission);
}
public List<Permission> getPermissions()
{
return permissions;
}
public void setPermissions(List<Permission> permissions)
{
this.permissions = permissions;
}
}
user class mapping :
<?xml version="1.0" encoding="UTF-8"?>
<hibernate-mapping>
<class name="model.User" table="user">
<id name="id" type="int" column="id">
<generator class="identity"/>
</id>
<property name="name" column="name" type="string"/>
<property name="password" column="password" type="string"/>
<list name="permissions" table="user_permission" lazy="false">
<key column="user_id"/>
<index column="id"/>
<many-to-many class="Permission" column="permission_id"/>
</list>
</class>
</hibernate-mapping>
my Permission class:
public class Permission
{
private int id;
private String name;
public Permission() {}
public Permission(int id, String name)
{
this.id=id;
this.name=name;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name=name;
}
public int getId()
{
return id;
}
public void setId(int id)
{
this.id=id;
}
public boolean equals(Object obj)
{
return ((Permission)obj).id==id;
}
}
Permission class mapping :
<?xml version="1.0" encoding="UTF-8"?>
<hibernate-mapping>
<class name="model.Permission" table="permission">
<id name="id" type="int" column="id">
<generator class="identity"/>
</id>
<property name="name" column="name" type="string"/>
</class>
</hibernate-mapping>
There is a missing packageName in many to many mapping. Change it from Permission to model.Permission. It should solve the problem. Below is the sippet
<class name="model.User" table="user">
<id name="id" type="int" column="id">
<generator class="identity"/>
</id>
<property name="name" column="name" type="string"/>
<property name="password" column="password" type="string"/>
<list name="permissions" table="user_permission" lazy="false">
<key column="user_id"/>
<index column="id"/>
<many-to-many class="model.Permission" column="permission_id"/>
</list>
</class> </hibernate-mapping>
I am reviewing my Java skills and your support to the community is amazing, your tips have helped me a lot.
I am stuck in a Hibernate #OneToOne configuration, it is a very simple design and code but I can´t find the error. I´d really appreciate your help.
This is the user.java code, the user_id is generated by an autoincrement column at MySQL. I have omitted hash() and equals() code for simplicity. Hibernate understands the User class but something is missing to get to the Address class that is at the other side of the relationship.
Any help would be very appreciated.
Thank you
1) This is the user.java:
package myPackage;
import java.io.Serializable;
import java.util.Arrays;
import javax.persistence.*;
#Entity
#Table(name="user1")
public class User implements Serializable {
private static final long serialVersionUID = 3271213543123246487L;
#Id
#GeneratedValue
#Column(name="user_id")
private Integer user_id;
#Column(name="user_name", length=100, nullable=false)
private String user_name;
#OneToOne (cascade= CascadeType.ALL)
#PrimaryKeyJoinColumn(name="user_id")
private Address myAddress;
public Integer getUser_id() {
return user_id;
}
public void setUser_id(Integer user_id) {
this.user_id = user_id;
}
public String getUser_name() {
return user_name;
}
public void setUser_name(String user_name) {
this.user_name = user_name;
}
public Address getMyAddress() {
return myAddress;
}
public void setMyAddress(Address myAddress) {
this.myAddress = myAddress;
}
}
2) This is the Address.java code:
package myPackage;
import java.io.Serializable;
import javax.persistence.*;
import org.hibernate.annotations.Parameter;
#Entity
#Table(name="address1")
public class Address implements Serializable {
private static final long serialVersionUID = 3605176021936036836L;
#Id
#GeneratedValue(generator="address_ibfk_2")
#org.hibernate.annotations.GenericGenerator(name="address_ibfk_2",
strategy="foreign",parameters =#Parameter(name="property",value="user1"))
#Column(name="user_id")
private Integer user_id;
#Column(name="address_line1", length=100, nullable=false)
private String address_line1;
public String getAddress_line1() {
return address_line1;
}
public void setAddress_line1(String address_line1) {
this.address_line1 = address_line1;
}
}
3) This is the very simple TestUser class
public class TestUser {
public static void main(String[] args) {
Session mySession = HibernateUtil.getSessionFactory().openSession();
System.out.println("Connection status"+mySession.isConnected());
System.out.println("Session status"+mySession.isOpen());
Transaction myTransaction = mySession.beginTransaction();
try {
User myUser = new User();
Address myAddress = new Address();
myUser.setUser_name("TesteO2O");
myAddress.setAddress_line1("Rua A");
myUser.setMyAddress(myAddress);
mySession.save(myUser);
myTransaction.commit();
System.out.println("myUser saved sucessfully");
} catch (Exception e) {
e.printStackTrace();
myTransaction.rollback();
} finally {
mySession.close();
}
}
}
4) This is the hibernate.cfg.xml config file
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!--MySQL Config-->
<property name="dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost/p2pl_dev?serverTimezone=UTC</property>
<property name="connection.username">xyz</property>
<property name="connection.password">blabla</property>
<property name="current_session_context_class">thread</property>
<!--Connection Pool Config: max_statements cached, idle time in seconds-->
<property name="c3po.min_size">2</property>
<property name="c3po.max_size">3</property>
<property name="c3po.timeout">300</property>
<property name="c3po.max_stamentes">50</property>
<property name="c3po.idle_test_period">3000</property>
<!--Debug Config, show_sql=console, format_sql=legible -->
<property name="show_sql">true</property>
<property name="format_sql">true</property>
<property name="generate_statistics">true</property>
<property name="use_sql_comments">true</property>
<!-- Classes -->
<mapping class="myPackage.User"/>
<mapping class="myPackage.Address"/>
</session-factory>
</hibernate-configuration>
5) Finally the error trace
Hibernate:
/* insert myPackage.User
*/ insert
into
user1
(user_name)
values
(?)
java.lang.NullPointerException
at org.hibernate.tuple.entity.AbstractEntityTuplizer.getPropertyValue(AbstractEntityTuplizer.java:650)
at org.hibernate.persister.entity.AbstractEntityPersister.getPropertyValue(AbstractEntityPersister.java:4736)
at org.hibernate.id.ForeignGenerator.generate(ForeignGenerator.java:96)
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:117)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:209)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:194)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:114)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:90)
at org.hibernate.internal.SessionImpl.fireSaveOrUpdate(SessionImpl.java:684)
at org.hibernate.internal.SessionImpl.saveOrUpdate(SessionImpl.java:676)
at org.hibernate.engine.spi.CascadingActions$5.cascade(CascadingActions.java:235)
at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:350)
at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:293)
at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:161)
at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:118)
at org.hibernate.event.internal.AbstractSaveEventListener.cascadeAfterSave(AbstractSaveEventListener.java:460)
at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:294)
at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:194)
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:125)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:209)
at org.hibernate.event.internal.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:55)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:194)
at org.hibernate.event.internal.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:49)
at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:90)
at org.hibernate.internal.SessionImpl.fireSave(SessionImpl.java:715)
at org.hibernate.internal.SessionImpl.save(SessionImpl.java:707)
at org.hibernate.internal.SessionImpl.save(SessionImpl.java:702)
at myPackage.TestUser.main(TestUser.java:26)
I have multiple objects meaning various steps (each object is a step) from a flux, they are to be persisted in the DB.
I was thinking on creating a relational table, where I would have each association, only one relation per row. something like, per example:
Steps: Id, Course_Id, Evaluation_Id, ProcessEvaluation_Id
and to clarify:
StepsForClass: id, class_id, steps_id
Course:id, someMoreinfo
Evaluation: id, someOtherinfo
and so on...
to be referenced in the table:
Class: Id, StepsForClass_id, someInfo
How could I map this into something like:
public class Klass
{
public uint Id { get; set; }
public IList<Step> Steps { get; set; }
}
public abstract class Step
{
public uint Id { get; set; }
public abstract void Apply();
}
public class Course : Step
{
//( some more fields )
public override void Apply() { /* ... */ }
}
public class Evaluation : Step
{
//( some other more fields )
public override void Apply() { /* ... */ }
}
You can use inheritence mapping like this:
<class name="Step" table="STEP">
<id name="Id" type="Int64" column="STEP_ID">
<generator class="native"/>
</id>
<property name="Amount" column="AMOUNT"/>
...
<joined-subclass name="Course" table="COURSE">
<key column="STEP_ID"/>
...
</joined-subclass>
<joined-subclass name="Evaluation" table="EVALUATION">
<key column="STEP_ID"/>
...
</joined-subclass>
</class>
For further reading: inheritance mapping
i googled a lot and did follow many tutorials about it, but i didnt get it to work. I have a many-to-many relation between the table Player and Type. Both tables are connected via typeperplayer. In the table typeperplayer is an additional column paid, which i want to use in hibernate.
Here is the database scheme:
Player:
Play_ID : int
Play_FirstName : string
Play_LastName : string
Typeperplayer:
Typl_ID : int
Typl_Play_ID : int
Typl_Type_ID : int
Typl_Paid : int
Type
Type_ID : int
Type_Name : string
Here is my Hibernate-Mapping:
Player:
<hibernate-mapping>
<class name="de.tt.treg.server.domain.Player" table="player">
<id name="id" type="java.lang.Integer">
<column name="Play_ID" />
<generator class="identity" />
</id>
<property name="firstName" type="string">
<column name="Play_FirstName" length="255" not-null="false" unique="false" />
</property>
<property name="lastName" type="string">
<column name="Play_LastName" length="255" not-null="false" unique="false" />
</property>
<set name="competitions" table="typeperplayer"
inverse="true" lazy="false" fetch="select">
<key>
<column name="typl_play_id" not-null="true" />
</key>
<one-to-many class="de.tt.treg.server.domain.PlayerCompetition" />
</set>
</class>
PlayerCompetition (Typeperplayer)
<hibernate-mapping package="de.tt.treg.server.domain">
<class name="PlayerCompetition" table="typeperplayer">
<composite-id name="playerCompetitionPk"
class="PlayerCompetitionPk">
<key-property name="id" column="Typl_Play_Id"
type="java.lang.Integer" />
<key-property name="id" column="Typl_Type_Id"
type="java.lang.Integer" />
</composite-id>
<property name="paid" type="java.lang.Integer">
<column name="Typl_Paid" length="10" not-null="false" unique="false" />
</property>
<many-to-one name="player" class="Player" insert="false" update="false"/>
<many-to-one name="competition" class="Competition" insert="false" update="false"/>
</class>
Competition (Type):
<hibernate-mapping>
<class name="de.tt.treg.server.domain.Competition" table="type">
<id name="id" type="java.lang.Integer">
<column name="Type_ID" />
<generator class="identity" />
</id>
<property name="name" type="string">
<column name="Type_Name" length="255" not-null="false" unique="false" />
</property>
<set name="players" table="typeperplayer"
inverse="false" lazy="true" fetch="select">
<key>
<column name="Type_Id" not-null="true" />
</key>
<one-to-many class="de.tt.treg.server.domain.PlayerCompetition" />
</set>
</class>
Additionally here are my classes:
public class Player{
private int id;
private String firstName;
private String lastName;
private Set<PlayerCompetition> competitions = new HashSet<PlayerCompetition>();
public Player() {
}
public Player(String firstName, String lastName,
Set<PlayerCompetition> competitions) {
this.firstName = firstName;
this.lastName = lastName;
this.competitions = competitions;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public Set<PlayerCompetition> getCompetitions() {
return competitions;
}
public void setCompetitions(Set<PlayerCompetition> competitions) {
this.competitions = competitions;
}
}
public class PlayerCompetition {
private int id;
private int paid;
private PlayerCompetitionPk playerCompetitionPk;
public PlayerCompetition() {
}
public PlayerCompetition(int id, int paid,
PlayerCompetitionPk competitionPk) {
super();
this.id = id;
this.paid = paid;
this.playerCompetitionPk = competitionPk;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getPaid() {
return paid;
}
public void setPaid(int paid) {
this.paid = paid;
}
public PlayerCompetitionPk getPlayerCompetitionPk() {
return playerCompetitionPk;
}
public void setPlayerCompetitionPk(PlayerCompetitionPk playerCompetitionPk) {
this.playerCompetitionPk = playerCompetitionPk;
}
public Player getPlayer() {
return getPlayerCompetitionPk().getPlayer();
}
public void setPlayer(Player player) {
getPlayerCompetitionPk().setPlayer(player);
}
public Competition getCompetition() {
return getPlayerCompetitionPk().getCompetition();
}
public void setCompetition(Competition competition) {
getPlayerCompetitionPk().setCompetition(competition);
}
}
public class PlayerCompetitionPk {
private int id;
private Player player;
private Competition competition;
public PlayerCompetitionPk() {
}
public int getId() {
return id;
}
public Player getPlayer() {
return player;
}
public void setPlayer(Player player) {
this.player = player;
}
public Competition getCompetition() {
return competition;
}
public void setCompetition(Competition competition) {
this.competition = competition;
}
public void setId(int id) {
this.id = id;
}
}
public class Competition {
private int id;
private String name;
private Set<PlayerCompetition> players;
public Competition() {
}
public Competition(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<PlayerCompetition> getPlayers() {
return players;
}
public void setPlayers(Set<PlayerCompetition> players) {
this.players = players;
}
}
I hope somebody can help me. If you need some additional information, you will get it ;-). Thank you.
Here is the generated sql statement:
select player0_.Play_ID as Play1_1_2_, player0_.Play_Club_ID as Play2_1_2_, player0_.Play_User_ID as Play3_1_2_, player0_.Play_FirstName as Play4_1_2_, player0_.Play_LastName as Play5_1_2_, player0_.Play_BirthDate as Play6_1_2_, team1_.Club_ID as Club1_0_0_, team1_.Club_Name as Club2_0_0_, team1_.Club_ShortName as Club3_0_0_, team1_.Club_Verband as Club4_0_0_, user2_.User_ID as User1_4_1_, user2_.User_Name as User2_4_1_, user2_.User_Passwort as User3_4_1_, user2_.User_RegisterDate as User4_4_1_ from player player0_ inner join club team1_ on player0_.Play_Club_ID=team1_.Club_ID inner join user user2_ on player0_.Play_User_ID=user2_.User_ID where player0_.Play_ID=?
In this statement are two joins with the other tables club and users. But there is no join with via typeperplayer.
The solution is to not directly map the player and type entities with a many-to-many relation, but instead have an intermediate entity playertype which you connect with one-to-many to both player and type.
That way you can use additional columns as properties on the playertype entity.
player <1-*> playertype <*-1> type
Edit:
Here's a nice example from mkyong
http://www.mkyong.com/hibernate/hibernate-many-to-many-example-join-table-extra-column-annotation/
Hi I want to have a unique last name and first name for my person table in my database .
my hibernate xml map for person is
package com.me.POJO;
public class Person {
private int personId;
private String firstName;
private String lastName;
private String streetAddress;
private String aptNo;
private String city;
private int zipCode;
public Person(){}
public Person(String firstName, String lastName, String streetAddress,
String aptNo, String city, int zipCode) {
this.firstName = firstName;
this.lastName = lastName;
this.streetAddress = streetAddress;
this.aptNo = aptNo;
this.city = city;
this.zipCode = zipCode;
}
public int getPersonId() {
return personId;
}
public void setPersonId(int personId) {
this.personId = personId;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getStreetAddress() {
return streetAddress;
}
public void setStreetAddress(String streetAddress) {
this.streetAddress = streetAddress;
}
public String getAptNo() {
return aptNo;
}
public void setAptNo(String aptNo) {
this.aptNo = aptNo;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public int getZipCode() {
return zipCode;
}
public void setZipCode(int zipCode) {
this.zipCode = zipCode;
}
}
my Hibernate hbm.xml file for person is :
<?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 Apr 9, 2012 2:49:54 PM by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping>
<class name="com.me.POJO.Person" table="Person">
<id name="personId" type="int">
<column name="personId_PK" />
<generator class="native"></generator>
</id>
<property name="aptNo" type="java.lang.String">
<column name="aptNo" />
</property>
<property name="city" type="java.lang.String">
<column name="city" />
</property>
<property name="firstName" type="java.lang.String">
<column name="firstName" />
</property>
<property name="lastName" type="java.lang.String">
<column name="lastName" />
</property>
<property name="streetAddress" type="java.lang.String">
<column name="streetAddress" />
</property>
<property name="zipCode" type="int">
<column name="zipCode" not-null="true" />
</property>
</class>
</hibernate-mapping>
is there any way i can add unique constraint in the person mapping in the hbm file so that my first name and last name are unique in the database/
Thanks a lot in advance.
You can make a natural key that containing last name and first name using the <natural-id> element.
Please note that <natural-id> only help to create an unique constraint on the natural key columns when the table schema is generated by Hibernate hbm2ddl . Hibernate will not do any uniqueness validation on <natural-id> columns at the run-times.
So , if you don't plan to re-create the table schema using Hibernate , you can simply manually adding the unique constraint for these columns using DDL and let the database check the uniqueness.