How to compile BIMLScript depending on generated code - ssis

I'm using BIML to create a ScriptComponenteSource, with a ScriptComponentProject.
The project contains the following (which is taken from the Varigence samples)
<ScriptProjects>
<ScriptComponentProject Name="SC_AD-Accounts" TargetFrameworkVersion="NetFX461">
<AssemblyReferences>
<AssemblyReference AssemblyPath="System" />
<AssemblyReference AssemblyPath="System.Data" />
<AssemblyReference AssemblyPath="System.Windows.Forms" />
<AssemblyReference AssemblyPath="System.Xml" />
<AssemblyReference AssemblyPath="Microsoft.SqlServer.TxScript" />
<AssemblyReference AssemblyPath="Microsoft.SqlServer.DTSRuntimeWrap" />
<AssemblyReference AssemblyPath="Microsoft.SqlServer.DTSPipelineWrap" />
<AssemblyReference AssemblyPath="Microsoft.SqlServer.PipelineHost" />
<AssemblyReference AssemblyPath="System.DirectoryServices" />
</AssemblyReferences>
<OutputBuffers>
<OutputBuffer Name="Output0">
<Columns>
<Column Name="UUId" DataType="String" Length="255" />
<Column Name="Surname" DataType="String" Length="255" />
<Column Name="GivenName" DataType="String" Length="255" />
<Column Name="EmailAddress" DataType="String" Length="255" />
<Column Name="UPN" DataType="String" Length="255" />
</Columns>
</OutputBuffer>
</OutputBuffers>
<Files>
<File Path="main.cs"><![CDATA[
using System;
using System.Data;
using System.DirectoryServices;
using Microsoft.SqlServer.Dts.Pipeline;
using Microsoft.SqlServer.Dts.Pipeline.Wrapper;
using Microsoft.SqlServer.Dts.Runtime.Wrapper;
[Microsoft.SqlServer.Dts.Pipeline.SSISScriptComponentEntryPointAttribute]
public partial class ScriptMain : UserComponent
{
public override void CreateNewOutputRows()
{
/*
Add rows by calling the AddRow method on the member variable named "<Output Name>Buffer".
For example, call MyOutputBuffer.AddRow() if your output was named "MyOutput".
*/
var searchBaseNames = new [] {
"OU=UserP,OU=User,DC=MyDC",
"OU=UserPS,OU=User,DC=MyDC",
"OU=UserPSC,OU=User,DC=MyDC"
};
var propertiesToLoad = new [] {
"sn",
"givenName",
"mail",
"userPrincipalName",
"objectGuid",
"serialNumber"
};
foreach (var searchBaseName in searchBaseNames) {
var searchBaseEntry = new DirectoryEntry("LDAP://" + searchBaseName);
var directorySearcher = new DirectorySearcher(searchBaseEntry, "(objectClass=user)", propertiesToLoad, SearchScope.Subtree) {
PageSize = 2500
};
foreach (SearchResult searchResult in directorySearcher.FindAll()) {
var surname = searchResult.Properties["sn"][0] as string;
var givenName = searchResult.Properties["givenName"][0] as string;
var email = searchResult.Properties["mail"][0] as string;
var upn = searchResult.Properties["userPrincipalName"][0] as string;
string uuid = null;
if(searchResult.Properties.Contains("serialNumber"))
{
uuid = searchResult.Properties["serialNumber"][0] as string;
if(!string.IsNullOrEmpty(uuid))
uuid = uuid;
}
if(string.IsNullOrEmpty(uuid))
{
var objectGuidBytes = searchResult.Properties["objectGuid"][0] as byte[];
var objectGuid = new Guid(objectGuidBytes);
uuid = objectGuid.ToString();
}
if(string.IsNullOrEmpty(surname) || string.IsNullOrEmpty(givenName) ||
string.IsNullOrEmpty(upn) || string.IsNullOrEmpty(email))
{
continue;
}
Output0Buffer.AddRow();
Output0Buffer.Surname = surname;
Output0Buffer.GivenName = givenName;
Output0Buffer.UPN = upn;
Output0Buffer.EmailAddress = email;
}
}
}
}
]]></File>
</Files>
</ScriptComponentProject>
</ScriptProjects>
This will not compile, due to the BIML-expansion not knowing about Output0Buffer and the overriden method (they will be created automatically).
Is there a way to resolve this hen-egg-problem?

I blogged about it,
https://billfellows.blogspot.com/2015/10/biml-script-component-source.html
You need to specify the IsSynchronous property as false for the output buffer. Otherwise, it will treat the component as a synchronous transformation.
<OutputBuffer Name="Output0" IsSynchronous="false">
Good me on commenting my code
<OutputBuffers>
<!--
Define what your buffer is called and what it looks like
Must set IsSynchronous as false. Otherwise it is a transformation
(one row enters, one row leaves) and not a source.
-->
<OutputBuffer Name="DemoOutput" IsSynchronous="false">
<Columns>
<Column Name="SourceColumn" DataType="String" Length="50" />
</Columns>
</OutputBuffer>
</OutputBuffers>

Related

SSIS OnVariableValueChanged not fired

I am generating a SSIS dtsx using BIML.
I want every change of a value of any variable to be logged.
I have several variables, all with RaiseChangeEvent at TRUE.
I have a OnVariableValueChanged event handler set for the package and for the dataflow where the variables are changed (by a Count Row).
When I execute the dtsx I see the handler is not even called.
I tried with other events and they are called.
So what is preventing the OnVariableValueChanged to be handled?
All the variables will be set to 0 or positive values and I made sure they start with a value of -1 in order to be sure there will actually be a change of value.
This seems to work for me. I create a variable with RaiseChangedEvent set to true. I then have a For Loop increment that value. I have a script task inside the for loop logging the value and an Event Handler attached to the package for the OnVariableValueChanged event. There I have a sequence container and a script task (disabled). If I put a breakpoint on the container, I can see that it is being called. Enabling the script task there, despite being the same code as in the control flow, results in a timeout error for locking the variable. /shrug
<!-- http://stackoverflow.com/q/42945383/181965 -->
<Biml xmlns="http://schemas.varigence.com/biml.xsd">
<Packages>
<Package Name="so_42945383" >
<Variables>
<Variable DataType="Int32" Name="IndexCurrent" RaiseChangedEvent="true">-1</Variable>
<Variable DataType="Int32" Name="IndexStart">0</Variable>
<Variable DataType="Int32" Name="IndexStop">1</Variable>
</Variables>
<Tasks>
<ForLoop Name="FLT Modify values" ConstraintMode="Linear">
<InitializerExpression><![CDATA[#[User::IndexCurrent] = #[User::IndexStart]]]></InitializerExpression>
<LoopTestExpression><![CDATA[#[User::IndexCurrent] <= #[User::IndexStop]]]></LoopTestExpression>
<CountingExpression><![CDATA[#[User::IndexCurrent] = #[User::IndexCurrent] + 1]]></CountingExpression>
<Tasks>
<Container Name="SEQC Do nothing" />
<Script ProjectCoreName="FLT_ST_EchoBack" Name="SCR Echo Back FLT">
<ScriptTaskProjectReference ScriptTaskProjectName="ST_EchoBack" />
</Script>
</Tasks>
</ForLoop>
</Tasks>
<Events>
<Event Name="OVVC" EventType="OnVariableValueChanged">
<Tasks>
<Container Name="SEQC Do nothing" />
<Script ProjectCoreName="OVCC_ST_EchoBack" Name="SCR Echo Back OVVC" Disabled="true">
<ScriptTaskProjectReference ScriptTaskProjectName="ST_EchoBack" />
</Script>
</Tasks>
</Event>
</Events>
</Package>
</Packages>
<ScriptProjects>
<ScriptTaskProject ProjectCoreName="ST_EchoBack" Name="ST_EchoBack" VstaMajorVersion="0">
<ReadOnlyVariables>
<!-- List all the variables you are interested in tracking -->
<Variable Namespace="User" VariableName="IndexCurrent" DataType="Int32" />
<Variable Namespace="User" VariableName="IndexStart" DataType="Int32" />
<Variable Namespace="User" VariableName="IndexStop" DataType="Int32" />
</ReadOnlyVariables>
<Files>
<File Path="ScriptMain.cs" BuildAction="Compile">using System;
using System.Data;
using Microsoft.SqlServer.Dts.Runtime;
using System.Windows.Forms;
namespace ST_EchoBack
{
[Microsoft.SqlServer.Dts.Tasks.ScriptTask.SSISScriptTaskEntryPointAttribute]
public partial class ScriptMain : Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase
{
public void Main()
{
bool fireAgain = false;
string message = "{0}::{1} : {2}";
foreach (var item in Dts.Variables)
{
Dts.Events.FireInformation(0, "SCR Echo Back", string.Format(message, item.Namespace, item.Name, item.Value), string.Empty, 0, ref fireAgain);
}
Dts.TaskResult = (int)ScriptResults.Success;
}
enum ScriptResults
{
Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success,
Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure
};
}
} </File>
<File Path="Properties\AssemblyInfo.cs" BuildAction="Compile">
using System.Reflection;
using System.Runtime.CompilerServices;
[assembly: AssemblyVersion("1.0.*")]
</File>
</Files>
<AssemblyReferences>
<AssemblyReference AssemblyPath="System" />
<AssemblyReference AssemblyPath="System.Data" />
<AssemblyReference AssemblyPath="System.Windows.Forms" />
<AssemblyReference AssemblyPath="System.Xml" />
<AssemblyReference AssemblyPath="Microsoft.SqlServer.ManagedDTS.dll" />
<AssemblyReference AssemblyPath="Microsoft.SqlServer.ScriptTask.dll" />
</AssemblyReferences>
</ScriptTaskProject>
</ScriptProjects>
</Biml>

Foreach NodeList Enumerator in biml

i have a foreach loop which traverse through the xml.
i know how to add this kind of foreach in SSIS. but not able to find the code snippet of biml for the same.
how to mentioned below properties in foreachloopcontainer in biml
Enumerator= Foreach NodeList Enumerator
DocumentSourceType=Variable
DocumentSource
EnumerationType = NodeText
OuterXPathStringSourceType= DirectInput
OuterXPathString = /ROOT/*
any help in having sample code for writing foreachloopcontainer with nodelist enumerator would be a greate help!!!
If you'd like to use a variable as your input source, then you're looking for VariableInput
EnumerationType is exposed in the ForEachNodeListLoop
DirectOuterXPath is where you specify your OuterXPathStringSource, like <DirectOuterXPath>/ROOT/*</DirectOuterXPath>
While not an exact representation of your request (I use Variables across the board), to shred<Files><File>Foo.txt</File><File>Bar.txt</File><File>Blee.txt</File></Files> into Foo.txt, Bar.txt and Blee.txt
<Biml xmlns="http://schemas.varigence.com/biml.xsd">
<Packages>
<Package Name="so_36759813">
<Variables>
<Variable DataType="String" Name="CurrentNode"></Variable>
<Variable DataType="String" Name="SourceXML"><![CDATA[<Files><File>Foo.txt</File><File>Bar.txt</File><File>Blee.txt</File></Files>]]></Variable>
<Variable DataType="String" Name="OuterXPath"><![CDATA[/Files/File]]></Variable>
<Variable DataType="String" Name="InnerXPath"><![CDATA[.]]></Variable>
</Variables>
<Tasks>
<ForEachNodeListLoop
Name="FENLL Shred XML"
EnumerationType="ElementCollection"
InnerElementType="NodeText"
>
<VariableInput VariableName="User.SourceXML" />
<VariableOuterXPath VariableName="User.OuterXPath" />
<VariableInnerXPath VariableName="User.InnerXPath" />
<VariableMappings>
<VariableMapping VariableName="User.CurrentNode" Name="0" />
</VariableMappings>
<Tasks>
<Script ProjectCoreName="ST_EchoBack" Name="SCR Echo Back">
<ScriptTaskProjectReference ScriptTaskProjectName="ST_EchoBack" />
</Script>
</Tasks>
</ForEachNodeListLoop>
</Tasks>
</Package>
</Packages>
<ScriptProjects>
<ScriptTaskProject ProjectCoreName="ST_EchoBack" Name="ST_EchoBack" VstaMajorVersion="0">
<ReadOnlyVariables>
<Variable Namespace="User" VariableName="CurrentNode" DataType="String" />
</ReadOnlyVariables>
<Files>
<File Path="ScriptMain.cs" BuildAction="Compile">using System;
using System.Data;
using Microsoft.SqlServer.Dts.Runtime;
using System.Windows.Forms;
namespace ST_EchoBack
{
[Microsoft.SqlServer.Dts.Tasks.ScriptTask.SSISScriptTaskEntryPointAttribute]
public partial class ScriptMain : Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase
{
public void Main()
{
bool fireAgain = false;
string message = "{0}::{1} : {2}";
foreach (var item in Dts.Variables)
{
Dts.Events.FireInformation(0, "SCR Echo Back", string.Format(message, item.Namespace, item.Name, item.Value), string.Empty, 0, ref fireAgain);
}
Dts.TaskResult = (int)ScriptResults.Success;
}
enum ScriptResults
{
Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success,
Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure
};
}
} </File>
<File Path="Properties\AssemblyInfo.cs" BuildAction="Compile">
using System.Reflection;
using System.Runtime.CompilerServices;
[assembly: AssemblyVersion("1.0.*")]
</File>
</Files>
<AssemblyReferences>
<AssemblyReference AssemblyPath="System" />
<AssemblyReference AssemblyPath="System.Data" />
<AssemblyReference AssemblyPath="System.Windows.Forms" />
<AssemblyReference AssemblyPath="System.Xml" />
<AssemblyReference AssemblyPath="Microsoft.SqlServer.ManagedDTS.dll" />
<AssemblyReference AssemblyPath="Microsoft.SqlServer.ScriptTask.dll" />
</AssemblyReferences>
</ScriptTaskProject>
</ScriptProjects>
</Biml>

xml Hibernate mapping, many to one with composite ids and different column names

I am a beginner in hibernate. Basically I want to make UserId1 and UserId2 foreign keys of UserId. I Know I need to use many to one and one to many, but I can't seem to understand how to use them because my columns have different names. Any help is appreciated!
This is my hibernate.hbm.xml file
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="objects.UserProfile" table="userProfiles">
<id name="UserId" column="UserProfileId">
<generator class="native"/>
</id>
<set name="userTracks" table="userTrack"
inverse="true" lazy="true" fetch="select">
<key>
<column name="UserProfileId" not-null="true" />
</key>
<one-to-many class="objects.UserTrack" />
</set>
</class>
<class name="objects.UserTrack" table="userTrack">
<composite-id>
<key-property name="UserId1" column="UserProfileId1" type="integer" />
<key-property name="UserId2" column="UserProfileId2" type="integer" />
</composite-id>
</class>
</hibernate-mapping>
So basically both ids in my track class should point to the id in the profile class
my userTrack class:
public class UserTrack implements Serializable {
private int UserProfileId1;
private int UserProfileId2;
public int getUserProfileId1() {
return UserProfileId1;
}
public void setUserProfileId1(int userProfiletId1) {
UserProfiletId1 = userProfileId1;
}
public int getUserProfileId2() {
return UserProfileId2;
}
public void setUserProfileId2(int userProfileId2) {
UserProfileId2 = userProfileId2;
}
}
My profile class:
public class UserProfile {
private int UserProfileId;
public int getUserProfileId() {
return UserProfileObjectId;
}
public void setUserProfileId(int userProfileId) {
UserProfileId = userProfileId;
}
}
The mappings should be as follows.
Since there is a One to Many relation between UserProfile and UserTrack,
you can use a Set<UserTracks> userTracks in UserProfile to keep track of the UserTracks for each UserProfile
For UserProfile Class
<hibernate-mapping>
<class name="objects.UserProfile" table="userProfiles">
<id name="userProfileId" column="UserProfileId">
<generator class="native"/>
</id>
<!-- other property definitions should come here -->
<set name="userTracks" table="userTrack"
inverse="true" lazy="true" fetch="select">
<key>
<column name="UserProfileId" not-null="true" />
</key>
<one-to-many class="objects.UserTrack" />
</set>
</class>
</hibernate-mapping>
For UserTrack class
<hibernate-mapping>
<class name="objects.UserTrack" table="userTrack">
<id name="userId" type="java.lang.String">
<column name="userTrackName" />
</id>
<many-to-one name="userProfile" class="objects.UserProfile" fetch="select">
<column name="UserProfileId" not-null="true" />
</many-to-one>
<!-- other property definitions should come here -->
</class>
</hibernate-mapping>
These two xml config files can be integrated to the main hibernate.cfg.cml file as follows.
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">xxxxxxxxxx</property>
<property name="hibernate.connection.url">xxxxxxxx</property>
<property name="hibernate.connection.username">username</property>
<property name="hibernate.connection.password">password</property>
<property name="hibernate.dialect">xxxxxx</property>
<property name="show_sql">true</property>
<property name="format_sql">true</property>
<mapping resource="path to this file/UserProfile.hbm.xml" />
<mapping resource="path to this file/UserTrack.hbm.xml" />
</session-factory>
</hibernate-configuration>
Hope this helps.
More info here
EDIT : I think Your Entity Classes should be like something similar to the following.
public class UserTrack implements Serializable {
// consider this as the primary key for UserTrack or feel free to change.
private String userTrackName;
// private int UserProfileId1;
// private int UserProfileId2;
// other attributes related to UserTrack
}
And
public class UserProfile {
// you could keep track of the UserTracks that belongs to a
//particular UserProfile in the Set.
// Now a UserProfile can belong to many UserTracks. Not just 2.
private Set<UserTrack> userTracks = new HashSet<>();
private int UserProfileId;
public int getUserProfileId() {
return UserProfileObjectId;
}
public void setUserProfileId(int userProfileId) {
UserProfileId = userProfileId;
}
}

Using Jackson 2.2 to serialize Hibernate result into JSON string, infinite loop

I have a bi-directional relationship between 2 objects - EvalMasterEvaluation (one) and EvalMasterEvalDetail (many). I've tried a number of different solutions, but I must be implementing them wrong. My goal is to return a list of details for a given eval id.
I'm using Jackson 2.2 (with databind and datatype-hibernate3 libs), hibernate 3.6 and spring 3.2.1. Some code omitted to make this easier to read.
The parent class:
#JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
#JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="#id")
public class EvalMasterEvaluation implements java.io.Serializable {
private BigDecimal id;
#JsonManagedReference private Set<EvalMasterEvalDetail> evalMasterEvalDetails = new HashSet<EvalMasterEvalDetail>(
0);
}
The child class:
#JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
#JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="#id")
public class EvalMasterEvalDetail implements java.io.Serializable {
private BigDecimal id;
#JsonBackReference private EvalMasterEvaluation evalMasterEvaluation;
private String active;
}
My Hibernate Criteria query:
Criteria criteria = session.createCriteria(EvalMasterEvalDetail.class)
.add(Restrictions.eq("active", "Y"))
.setFetchMode("evalMasterEvaluation", FetchMode.JOIN)
.createAlias("evalMasterEvaluation", "eval")
.add(Restrictions.eq("eval.id", evalId))
.addOrder(Order.asc("detailOrder"));
details = criteria.list();
ObjectMapper mapper = new ObjectMapper();
json = mapper.writeValueAsString(details);
EvalMasterEvaluation mapping
<hibernate-mapping>
<class name="org.anes.surveys.domain.EvalMasterEvaluation" table="EVAL_MASTER_EVALUATION">
<id name="id" type="big_decimal">
<column name="ID" precision="22" scale="0" />
<generator class="sequence-identity" >
<param name="sequence">EVAL_MASTER_EVALUATION_SEQ</param>
</generator>
</id>
<set name="evalMasterEvalDetails" table="EVAL_MASTER_EVAL_DETAIL" inverse="true" lazy="true" fetch="select">
<key>
<column name="MASTER_EVAL_ID" precision="22" scale="0" not-null="true" />
</key>
<one-to-many class="org.anes.surveys.domain.EvalMasterEvalDetail" />
</set>
</class>
</hibernate-mapping>
EvalMasterEvalDetail mapping
<hibernate-mapping>
<class name="org.anes.surveys.domain.EvalMasterEvalDetail" table="EVAL_MASTER_EVAL_DETAIL">
<id name="id" type="big_decimal">
<column name="ID" precision="22" scale="0" />
<generator class="sequence-identity" >
<param name="sequence">EVAL_MASTER_EVAL_DETAIL_SEQ</param>
</generator>
</id>
<many-to-one name="evalMasterEvaluation" class="org.anes.surveys.domain.EvalMasterEvaluation" fetch="select">
<column name="MASTER_EVAL_ID" precision="22" scale="0" not-null="true" />
</many-to-one>
<property name="active" type="string">
<column name="ACTIVE" length="1" not-null="true" />
</property>
</class>
</hibernate-mapping>
AYE! After 2 days I finally found my mistake. I forgot to register the Hibernate3Module. My criteria/mapper code is now:
Criteria criteria = session.createCriteria(EvalMasterEvalDetail.class)
.add(Restrictions.eq("active", "Y"))
.setFetchMode("evalMasterEvaluation", FetchMode.JOIN)
.createAlias("evalMasterEvaluation", "eval")
.add(Restrictions.eq("eval.id", evalId))
.addOrder(Order.asc("detailOrder"));
details = criteria.list();
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new Hibernate3Module());
json = mapper.writeValueAsString(details);
evalMasterEvaluation values are missing, but it's a step in the right direction.

hibernate many-to-many association and spring hibernatetemplate doesn't work

I am using Spring HibernateTemplate, OpenSessionInViewFilter(actually I extended this class and created my own to switch to FLUSH.AUTO Mode) and Mysql for implementing hibernate many-to-many association. However when I save an object, corresponding many-to-many table's values are not inserted. Does anybody can help me? Thank you.
here is the mapping xml
<hibernate-mapping>
<class name="com.intelli.epub.domain.Content" table="CONTENT">
<id name="id" type="java.lang.Long">
<column name="ID" />
<generator class="native" />
</id>
<property name="title" type="java.lang.String">
<column name="TITLE" />
</property>
<property name="text" type="java.lang.String">
<column name="TEXT" />
</property>
<many-to-one name="writer" class="com.intelli.epub.domain.User" fetch="join">
<column name="WRITER" />
</many-to-one>
<property name="createdDate" type="java.util.Date">
<column name="CREATEDDATE" />
</property>
<set name="menus" table="MENU_CONTENT" cascade="all">
<key column="CONTENT_ID"></key>
<many-to-many column="MENU_ID" class="com.intelli.epub.domain.Menu"/>
</set>
</class>
</hibernate-mapping>
another one:
<hibernate-mapping>
<class name="com.intelli.epub.domain.Menu" table="MENU">
<id name="id" type="java.lang.Long">
<column name="ID" />
<generator class="native" />
</id>
<property name="text" type="java.lang.String">
<column name="TEXT" />
</property>
<set name="contents" table="MENU_CONTENT" inverse="true">
<key column="MENU_ID"></key>
<many-to-many column="CONTENT_ID" class="com.intelli.epub.domain.Content"/>
</set>
</class>
and when saving like this:
Content content = new Content();
content.setCreatedDate(new Date());
content.setWriter(some user here);
content.setText("some text here");
Menu menu1 = new Menu("menu1");
Menu menu2 = new Menu("menu2");
Set<Menu> menus = new HashSet();
menus.add(menu1);
menus.add(menu2);
content.setMenus(menus);
contentDao.saveOrUpdate(content);
Now menu1 and menu2 would be saved in the MENU table, However nothing happens to MENU_CONTENT table; MENU_CONTENT table doesn't have a primary key field, instead MENU_ID and CONTENT_ID are primary key together. I don't know if it's the problem. Please help me. Thank you.
I found a solution. Instead of using Spring HibernateTemplate. I wrapped it in regular session and transaction like this.
Session session = contentDao.getHibernateTemplate().getSessionFactory().getCurrentSession();
transaction = session.beginTransaction();
Content content = new Content();
content.setCreatedDate(new Date());
content.setWriter(some user here);
content.setText("some text here");
Menu menu1 = new Menu("menu1");
Menu menu2 = new Menu("menu2");
Set<Menu> menus = new HashSet();
menus.add(menu1);
menus.add(menu2);
content.setMenus(menus);
session.save(content);
transaction.commit();
session.close();
And here is my session filter which inherited from OpenSessionInViewFilter
public class SessionFilter extends OpenSessionInViewFilter {
protected Session getSession(SessionFactory sessionFactory)
throws DataAccessResourceFailureException {
Session session = super.getSession(sessionFactory);
session.setFlushMode(FlushMode.AUTO);
return session;
}
}
Does anybody know a way to handle this without bothering to write session management myself?