These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 9 posts ] 
Author Message
 Post subject: Map does not cascade inserted objects
PostPosted: Fri Mar 06, 2009 5:08 am 
Regular
Regular

Joined: Wed Feb 11, 2009 10:58 am
Posts: 55
Hello,

I've got a small problem with a map and cascade.


My Objects + mappings:

Testspecification:

Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="ETToolV2" namespace="Continental.ETTool">
  <class name="Testspecification" table="ET_TESTSPECIFICATION" lazy="true">
    <id name="Id" column="ID_TESTSPECIFICATION" type="Decimal">
      <generator class="sequence">
        <param name="sequence">ET_TESTSPECIFICATION_SEQ</param>
      </generator>
    </id>
    <map name="VirtualIncarnations" table="ET_VIRTUALTESTSTEPDATA" lazy="true" cascade="all"  >
      <key column="ID_TESTSPECIFICATION" />
      <index-many-to-many class="Teststep" column="ID_TESTSTEP"/>
      <one-to-many class="VirtualTeststepData"/>
    </map>
  </class>
</hibernate-mapping>


Code:
public class Testspecification
{
    public virtual Decimal Id { get; set; }


    protected virtual IDictionary<Teststep, VirtualTeststepData> VirtualIncarnations { get; set; }


    public Testspecification()
    {
      VirtualIncarnations = new Dictionary<Teststep, VirtualTeststepData>();
    }
}



VirtualTeststepData + VirtualTeststepDataKey:

Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="ETToolV2" namespace="Continental.ETTool">
  <class name="VirtualTeststepData" table="ET_VIRTUALTESTSTEPDATA" lazy="true" >
    <composite-id class="VirtualTeststepDataKey" name="Key">
      <key-many-to-one name="AssignedTestspecification" column="ID_TESTSPECIFICATION" class="Testspecification" />
      <key-many-to-one name="VirtualStep" column="ID_TESTSTEP" class="Teststep" />
    </composite-id>
    <property name="Parameter0" type="String" column="PARAMETER0" />
    <property name="Parameter1" type="String" column="PARAMETER1" />
    <property name="Parameter2" type="String" column="PARAMETER2" />
    <property name="Parameter3" type="String" column="PARAMETER3" />
    <property name="Confirmed" type="Decimal" column="CONFIRMED" />
    <property name="CreationDate" type="DateTime" column="CREATION_DATE" />
  </class>
</hibernate-mapping>


Code:
public class VirtualTeststepData
{
    public virtual VirtualTeststepDataKey Key { get; set; }
    public virtual String Parameter0 { get; set; }
    public virtual String Parameter1 { get; set; }
    public virtual String Parameter2 { get; set; }
    public virtual String Parameter3 { get; set; }
    //public virtual Teststep VirtualStep { get; set; }
    //public virtual Testspecification AssignedTestspecification { get; set; }
    public virtual Decimal Confirmed { get; set; }
    public virtual DateTime CreationDate { get; set; }


    public VirtualTeststepData()
    {
      this.Confirmed = 0;
      CreationDate = DateTime.Now;
      Key = new VirtualTeststepDataKey();
    }


    public override bool Equals(object obj)
    {
      return base.Equals(obj);
    }


    public override int GetHashCode()
    {
      return base.GetHashCode();
    }


    public override string ToString()
    {
      return base.ToString();
    }
  }


Code:
  public class VirtualTeststepDataKey: ISerializable
  {
    public virtual Testspecification AssignedTestspecification { get; set; }
    public virtual Teststep VirtualStep { get; set; }


    #region ISerializable Member


    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
      throw new NotImplementedException();
    }


    #endregion


    public override bool Equals(object obj)
    {
      if (obj.GetType() != typeof(VirtualTeststepDataKey))
        return false;


      VirtualTeststepDataKey compareKey = (VirtualTeststepDataKey)obj;


      return (compareKey.AssignedTestspecification.Id == this.AssignedTestspecification.Id) && (compareKey.VirtualStep.Id == this.VirtualStep.Id);
    }


    public override int GetHashCode()
    {
      return base.GetHashCode();
    }
  }
}


I use it like the following:

Code:
public virtual VirtualTeststepData GetVirtualTeststepData(Teststep
teststep, Testspecification testspecification)
{
  result = new VirtualTeststepData();
  result.Key.AssignedTestspecification = testspecification;
  result.Key.VirtualStep = teststep;
  this.VirtualIncarnations.Add(teststep, result);


  return result;
}


if I do a Session.Save(testspecification) later in my code everything
works fine, but there is no INSERT statement for VirtualTeststepData I
created in the function above, though it creates an Update statement to attach the VirtualTeststepData to the Testspecification. Anybody got an idea how I could solve this?

Thanks for your help =)


Greetings,
Reflection


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 06, 2009 6:23 am 
Expert
Expert

Joined: Thu Dec 14, 2006 5:57 am
Posts: 1185
Location: Zurich, Switzerland
Hibernate can't decide if your item is new or not:

Quote:
Since a composite identifier must be assigned to the object before saving it, we can't use unsaved-value of the identifier to distinguish between newly instantiated instances and instances saved in a previous session.
You may instead implement IInterceptor.IsUnsaved() if you wish to use SaveOrUpdate() or cascading save / update. As an alternative, you may also set the unsaved-value attribute on a <version> (or <timestamp>) element to specify a value that indicates a new transient instance. In this case, the version of the entity is used instead of the (assigned) identifier and you don't have to implement IInterceptor.IsUnsaved() yourself.

_________________
--Wolfgang


Top
 Profile  
 
 Post subject:
PostPosted: Mon Mar 09, 2009 12:10 pm 
Regular
Regular

Joined: Wed Feb 11, 2009 10:58 am
Posts: 55
Thank you very much!!!!

I think I would have never found that :) works like a charm now.

Is there another IInterceptor Interface? The only one I know is the one for Sessions, but that doesn't support IsUnsaved(). Is ther another IInterceptor Interface I can use anywhere else?

Thanks in advance!

Reflection


Top
 Profile  
 
 Post subject:
PostPosted: Mon Mar 09, 2009 12:36 pm 
Expert
Expert

Joined: Thu Dec 14, 2006 5:57 am
Posts: 1185
Location: Zurich, Switzerland
There's only NHibernate.IInterceptor. This interface has an IsUnsaved(..) method. YOu can start your work with subclassing EmptyInterceptor.

_________________
--Wolfgang


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 10, 2009 4:44 am 
Regular
Regular

Joined: Wed Feb 11, 2009 10:58 am
Posts: 55
This is the Empty class, when I implement an Interceptor. I already did this, because I needed an OnFlushDirty(...) Handler.

There is no IsUnsaved(...). Maybe you mean IsTransient(...)?

Code:
class ETToolInterceptor: IInterceptor
{

    public void AfterTransactionBegin(ITransaction tx)
    {
     
    }

    public void AfterTransactionCompletion(ITransaction tx)
    {
     
    }

    public void BeforeTransactionCompletion(ITransaction tx)
    {
     
    }

    public int[] FindDirty(object entity, object id, object[] currentState, object[] previousState, string[] propertyNames, NHibernate.Type.IType[] types)
    {
      return null;
    }

    public object GetEntity(string entityName, object id)
    {
      return null;
    }

    public string GetEntityName(object entity)
    {
      return "";
    }

    public object Instantiate(string entityName, EntityMode entityMode, object id)
    {
      return null;
    }

    public bool? IsTransient(object entity)
    {
     
      return null;
    }

    public void OnCollectionRecreate(object collection, object key)
    {
     
    }

    public void OnCollectionRemove(object collection, object key)
    {
    }

    public void OnCollectionUpdate(object collection, object key)
    {
    }

    public void OnDelete(object entity, object id, object[] state, string[] propertyNames, NHibernate.Type.IType[] types)
    {

    }

    public bool OnFlushDirty(object entity, object id, object[] currentState, object[] previousState, string[] propertyNames, NHibernate.Type.IType[] types)
    {

    }

    public bool OnLoad(object entity, object id, object[] state, string[] propertyNames, NHibernate.Type.IType[] types)
    {
      return false;
    }

    public NHibernate.SqlCommand.SqlString OnPrepareStatement(NHibernate.SqlCommand.SqlString sql)
    {
      return sql;
    }

    public bool OnSave(object entity, object id, object[] state, string[] propertyNames, NHibernate.Type.IType[] types)
    {
      return false;
    }

    public void PostFlush(System.Collections.ICollection entities)
    {

    }

    public void PreFlush(System.Collections.ICollection entities)
    {

    }

    public void SetSession(ISession session)
    {

    }
  }
}


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 10, 2009 4:48 am 
Expert
Expert

Joined: Thu Dec 14, 2006 5:57 am
Posts: 1185
Location: Zurich, Switzerland
Which NHibernate version do you use ? I'm using 1.2 and my interface has the method !?

_________________
--Wolfgang


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 10, 2009 5:21 am 
Regular
Regular

Joined: Wed Feb 11, 2009 10:58 am
Posts: 55
I use the Version 2.0.1.GA Released: September 29, 2008

It is the Version stated as latest Version on http://www.hibernate.org/343.html


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 10, 2009 7:35 am 
Expert
Expert

Joined: Thu Dec 14, 2006 5:57 am
Posts: 1185
Location: Zurich, Switzerland
Hmm ... I doubt that the method was removed, but there is a better way with 2.0 anyway. Checkout the event system:

http://www.nhforge.org/doc/nh/en/index.html#objectstate-events

_________________
--Wolfgang


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 10, 2009 9:03 am 
Regular
Regular

Joined: Wed Feb 11, 2009 10:58 am
Posts: 55
OK... I've got an old Documentation then. It's for Version 1.2.0. Thought it was the actual version :)

But there's still no IsUnsaved(...) Event.

Code:
<xs:simpleType name="listenerType">
  <xs:restriction base="xs:string">
    <xs:enumeration value="auto-flush" />
    <xs:enumeration value="merge" />
    <xs:enumeration value="create" />
    <xs:enumeration value="create-onflush" />
    <xs:enumeration value="delete" />
    <xs:enumeration value="dirty-check" />
    <xs:enumeration value="evict" />
    <xs:enumeration value="flush" />
    <xs:enumeration value="flush-entity" />
    <xs:enumeration value="load" />
    <xs:enumeration value="load-collection" />
    <xs:enumeration value="lock" />
    <xs:enumeration value="refresh" />
    <xs:enumeration value="replicate" />
    <xs:enumeration value="save-update" />
    <xs:enumeration value="save" />
    <xs:enumeration value="pre-update" />
    <xs:enumeration value="update" />
    <xs:enumeration value="pre-load" />
    <xs:enumeration value="pre-delete" />
    <xs:enumeration value="pre-insert" />
    <xs:enumeration value="post-load" />
    <xs:enumeration value="post-insert" />
    <xs:enumeration value="post-update" />
    <xs:enumeration value="post-delete" />
    <xs:enumeration value="post-commit-update" />
    <xs:enumeration value="post-commit-insert" />
    <xs:enumeration value="post-commit-delete" />
  </xs:restriction>
</xs:simpleType>


This is the IInterceptor Interface in my Version of NHibernate:

Code:
namespace NHibernate
{
  public interface IInterceptor
  {
    void AfterTransactionBegin(ITransaction tx);
    void AfterTransactionCompletion(ITransaction tx);
    void BeforeTransactionCompletion(ITransaction tx);
    int[] FindDirty(object entity, object id, object[] currentState, object[] previousState, string[] propertyNames, IType[] types);
    object GetEntity(string entityName, object id);
    string GetEntityName(object entity);
    object Instantiate(string entityName, EntityMode entityMode, object id);
   
    //
    // Zusammenfassung:
    //     Called when a transient entity is passed to SaveOrUpdate.
    //
    // Parameter:
    //   entity:
    //     A transient entity
    //
    // Rückgabewerte:
    //     Boolean or null to choose default behaviour
    //
    // Hinweise:
    //     The return value determines if the object is saved true - the entity is passed
    //     to Save(), resulting in an INSERT false - the entity is passed to Update(),
    //     resulting in an UPDATE null - Hibernate uses the unsaved-value mapping to
    //     determine if the object is unsaved
    bool? IsTransient(object entity);
   
    void OnCollectionRecreate(object collection, object key);
    void OnCollectionRemove(object collection, object key);
    void OnCollectionUpdate(object collection, object key);
    void OnDelete(object entity, object id, object[] state, string[] propertyNames, IType[] types);
    bool OnFlushDirty(object entity, object id, object[] currentState, object[] previousState, string[] propertyNames, IType[] types);
    bool OnLoad(object entity, object id, object[] state, string[] propertyNames, IType[] types);
    SqlString OnPrepareStatement(SqlString sql);
    bool OnSave(object entity, object id, object[] state, string[] propertyNames, IType[] types);
    void SetSession(ISession session);
  }
}


I left the documentation to IsTransient(...), because I think this matches the IsUnsaved function. Maybe you can do something like:

Code:
bool? IsTransient(object entity)
{
  if( entity.getType() == typeof(VirtualTeststepData) )
  {
    //Use another Session to determine if the instance is already in DB
    if( IsInDB )
      return true;
    else
      return false;
  }
  else
     return null;

}


Though I assume this would not be very performant if you do a lot of changes to different VirtualTeststepDatas.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 9 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.