NHibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session - nhibernate

I have an Class with property
[Serializable]
public class MyClass {
public MyClass ()
{
}
public virtual System.DateTime Time {
get;
set;
}
public virtual string Name {
get;
set;
}
public virtual string Department {
get;
set;
}
public virtual string Ip
{
get;
set;
}
public virtual string Address {
get;
set;
}
public override bool Equals(object obj)
{
if (obj == null)
return false;
MyClass t = obj as MyClass ;
if (t == null)
return false;
if (this.Time == t.Time && this.Name== t.Name && this.Department== t.Department)
return true;
else
return false;
}
public override int GetHashCode()
{
int hash = 13;
hash = hash +
(null == this.Time ? 0 : this.Time.GetHashCode());
hash = hash +
(null == this.Name? 0 : this.Name.GetHashCode());
hash = hash +
(null == this.Department ? 0 : this.Department.GetHashCode());
return hash;
}
}
I am having my Nhibernate mapping as
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="NhibernateTest" assembly="NhibernateTest">
<class name="MyClass" table="NhibernateTest">
<composite-id>
<key-property column="Time" type="DateTime" name="Time"></key-property>
<key-property name="Name" type="string" column="Name" ></key-property>
<key-property name="Department" type="string" column="Department" ></key-property>
</composite-id>
<property column="Ip" type="string" name="Ip" />
<property column="Address" type="string" name="Address" />
</class>
</hibernate-mapping>
I am trying to perform a bulk upload for some 40k data's with using composite key. using the following code.
public void StoreInRDBMS(List<MyClass> FileList)
{
ITransaction transaction = null;
try
{
var stopwatch = new Stopwatch();
stopwatch.Start();
ISession session = OpenSession();
using (transaction = session.BeginTransaction())
{
foreach (var File in FileList)
{
session.SaveOrUpdate(File);
}
session.Flush();
session.Clear();
transaction.Commit();
}
session.Close();
stopwatch.Stop();
var time = stopwatch.Elapsed;
}
catch (Exception ex)
{
transaction.Rollback();
}
}
but the problem is , while iterating in the loop the second record in the list throws this error
{"a different object with the same identifier value was already associated with the session: NhibernateTest.MyClass, of entity: NhibernateTest.MyClass"}
though the records are unique. and also if at all its not it should update the same.
It works file if I flush the session after every iteration in the loop like
foreach (var File in FileList)
{
session.SaveOrUpdate(File);
session.Flush();
session.Clear();
}
which should not be the case and even its talkin 17 mins for 40 k records if done by above method.
Can anybody help regarding the same.

Maybe?
foreach (var File in FileList)
{
session.SaveOrUpdate(File);
session.ExecuteUpdate();
}

Related

NHibernate multi column ManyToOne mapping with Mapping By-Code

I am trying to convert my FluentNHibernate mappings to NHibernate Mapping By-code using NHibernate 3.3.3. The goal is to upgrade to NHibernate 3.3.3 and to cut down on the number of assemblies being distributed.
However when I compile and run I get the following exception:
NHibernate.MappingException: Multi-columns property can't be mapped through single-column API.
The XML mapping FluentNHibernate gets my looks like this:
<many-to-one cascade="none" class="TextDto" fetch="join" lazy="false" name="Name" not-found="ignore">
<column name="NameTextId" unique="false" />
<column name="LanguageId" unique="false" />
</many-to-one>
Here is my new By-Code mapping:
this.ManyToOne(u => u.Name, c =>
{
c.Cascade(Cascade.None);
c.Class(typeof(TextDto));
c.Columns(
x =>
{
x.Name("NameTextId");
x.Unique(false);
},
x =>
{
x.Name("LanguageId");
x.Unique(false);
});
c.Fetch(FetchKind.Join);
c.Lazy(LazyRelation.NoLazy);
c.NotFound(NotFoundMode.Ignore);
c.Unique(false);
});
This is the old FluentNHibernate mapping:
References(x => x.Name)
.Columns("NameTextId", "LanguageId")
.Cascade.None()
.Fetch.Join()
.NotFound.Ignore()
.Not.Unique()
.Not.LazyLoad();
For Completeness the property type involved:
public class TextDto
{
public TextCompositeId Id { get; set; }
public string PluralText { get; set; }
public string SingularText { get; set; }
public override bool Equals(object obj)
{
var text = (TextDto)obj;
if (text == null) return false;
return this.Id.Equals(text.Id);
}
public override int GetHashCode()
{
return this.Id.GetHashCode();
}
}
And an example of the property in an entity:
public class CharacteristicValue
{
public CharacteristicValueCompositeId Id { get; set; }
public TextDto Name { get; set; }
public string LanguageIdentity { get; set; }
public string Value
{
get
{
string value = null;
if (this.ValueMultilingual != null) return this.ValueMultilingual.SingularText;
else if (!string.IsNullOrEmpty(this.ValueMeta)) return this.ValueMeta;
return value;
}
}
public TextDto ValueMultilingual { get; set; }
public string ValueMeta { get; set; }
public override bool Equals(object obj)
{
if (obj == null) return false;
if (object.ReferenceEquals(this, obj)) return true;
CharacteristicValue characteristicValue = obj as CharacteristicValue;
if (characteristicValue == null) return false;
if (this.Id != characteristicValue.Id) return false;
return true;
}
public override int GetHashCode()
{
return this.Id.GetHashCode();
}
}
So, how do I get the xml-mapping I used to get with FluentNHibernate but with NHiberbate's Mapping By-Code?
In your mapping, remove the c.Unique(false); from the ManyToOne mapping. This setting we do apply for each column now.
this.ManyToOne(u => u.Name, c =>
{
... // the same as above
// c.Unique(false); // it is setting now related to columns
});
And you will recieve
<many-to-one name="Name" class="TextDto" fetch="join" lazy="false" not-found="ignore">
<column name="NameTextId" unique="true" />
<column name="LanguageId" />
</many-to-one>
If you will change uniqueness on one of the columns:
x =>
{
x.Name("NameTextId");
x.Unique(true); // change here
},
The unique constraint would be added to that column:
<column name="NameTextId" unique="true" />

NHibernate - Could not compile the mapping document

It is my firs time using NHibernate, I'm getting source code for a program from my friend after that, the program is running well after that I'm trying to add "Stock.hbm.xml" as following:
`
<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
namespace="NBooks.Core.Models"
assembly="NBooks.Core">
<class name="Stock" table="Stocks" lazy="false">
<id name="ID">
<column name="Stock_ID" />
<generator class="identity" />
</id>
<property name="Stock_name" column="Stock_name" />
<property name="Comp_ID" column="Comp_ID" />
<property name="Stock_Code" column="Stock_Code" />
<property name="Address" column="Address" />
<property name="Nots" column="Nots" />
</class>
</hibernate-mapping>
`
with my class "Stock.cs"
using System;
using System.Collections.Generic;
namespace NBooks.Core.Models
{
public class Stock : BaseModel<Stock>
{
public virtual string Stock_name { get; set; }
public virtual string Stock_Code { get; set; }
public virtual int Comp_ID { get; set; }
public virtual string Notes { get; set; }
public virtual string Address { get; set; }
public virtual bool Inactive { get; set; }
public Stock()
{
}
public Stock(string name)
{
this.Stock_name = name;
}
}
public class StockEventArgs : EventArgs
{
public Stock Stock { get; set; }
public StockEventArgs(Stock Stock)
{
this.Stock = Stock;
}
}
public delegate void StockEventHandler(Stock sender, EventArgs e);
}
the Base model is:
using System;
using System.Collections.Generic;
using NBooks.Core.Util;
using NBooks.Data.NHibernate;
using NHibernate;
namespace NBooks.Core.Models
{
public interface IBaseModel
{
int Id { get; set; }
}
public class BaseModel<T> : IBaseModel
{
IList<string> errors = new List<string>();
public virtual int Id { get; set; }
public virtual bool HasErrors {
get { return errors.Count > 0; }
}
public virtual IList<string> Errors {
get { return errors; }
}
public BaseModel()
{
}
public virtual void Validate()
{
Errors.Clear();
}
public virtual void SaveOrUpdate()
{
ITransaction trans = null;
try {
ISession session = NHibernateHelper.OpenSession();
trans = session.BeginTransaction();
session.SaveOrUpdate(this);
session.Flush();
trans.Commit();
} catch (Exception ex) {
LoggingService.Error(ex.Message);
MessageService.ShowError(ex.Message);
trans.Rollback();
}
}
public virtual void Delete()
{
ITransaction trans = null;
try {
ISession session = NHibernateHelper.OpenSession();
trans = session.BeginTransaction();
session.Delete(this);
session.Flush();
trans.Commit();
} catch (Exception ex) {
LoggingService.Error(ex.Message);
MessageService.ShowError(ex.Message);
trans.Rollback();
}
}
public static T Read(int id)
{
return NHibernateHelper.OpenSession().Load<T>(id);
}
public static IList<T> FindAll()
{
return
NHibernateHelper.OpenSession().CreateCriteria(typeof(T)).List<T>();
}
}
}
when build it appers every thing is well and no errors , when run the error "NHibernate - Could not compile the mapping document Stock.hbm.xml" appears.
Thanx in advance
I noticed you have a typo in you XML:
<property name="Nots" column="Nots" />
I would suggest that you look into using Fluent NHibernate as well. It is strongly typed (for the most part) and the mapping files are easier to read and use lambda expressions so that you don't have to go the XML route.
Your mapping would instead look like this:
public class StockMap(): ClassMap<Stock>
{
public StockMap(){
Id(x => x.Id).Column("Stock_ID").GeneratedBy.Identity();
Map(x => x.Comp_ID);
Map(x => x.Address);
Map(x => x.Notes);
}
}
You have a typo in your mapping
<property name="Nots" column="Nots" />
should be
<property name="Notes" column="Nots" />

NHibernate: Composite key, one-to-one relation and "Error performing LoadByUniqueKey"

I have two classes. Class 1:
public class Einsatz
{
public virtual ProjNrPindex Id { get; set; }
public virtual Int32? Knr { get; set; }
public virtual String RessNr { get; set; }
public virtual String AdrNr { get; set; }
public virtual DateTime EndeIst { get; set; }
public virtual DateTime StartIst { get; set; }
public virtual DateTime ArbeitsbeginnIst { get; set; }
public virtual String Kennwort { get; set; }
public virtual Taetigkeit Taetigkeit { get; set; }
public Einsatz()
{
this.Id = new ProjNrPindex();
}
public class ProjNrPindex
{
public virtual Int32? Pindex { get; set; }
public virtual String ProjNr { get; set; }
public override Boolean Equals(Object obj)
{
if (obj as Einsatz == null)
{
return(false);
}
if (Object.ReferenceEquals(this, obj) == true)
{
return(true);
}
ProjNrPindex other = obj as ProjNrPindex;
if (Object.Equals(this.Pindex, other.Pindex) == false)
{
return(false);
}
if (Object.Equals(this.ProjNr, other.ProjNr) == false)
{
return(false);
}
return(true);
}
public override Int32 GetHashCode()
{
Int32 hash = 0;
hash += (this.Pindex != null) ? this.Pindex.GetHashCode() : 0;
hash += 1000 * ((this.ProjNr != null) ? this.ProjNr.GetHashCode() : 0);
return(hash);
}
}
public override bool Equals(object obj)
{
var other = obj as Einsatz;
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return this.Id.Equals(other.Id);
}
public override int GetHashCode()
{
unchecked
{
int hash = GetType().GetHashCode();
hash = (hash * 31) ^ this.Id.GetHashCode();
return hash;
}
}
}
Class 2:
public class Taetigkeit
{
public virtual ProjNrPindex Id { get; set; }
public virtual string Text { get; set; }
public virtual string RessNr { get; set; }
public virtual Einsatz Einsatz { get; set; }
public Taetigkeit()
{
this.Id = new ProjNrPindex();
}
public class ProjNrPindex
{
public virtual Int32? Pindex { get; set; }
public virtual String ProjNr { get; set; }
public override Boolean Equals(Object obj)
{
if (obj as Einsatz == null)
{
return (false);
}
if (Object.ReferenceEquals(this, obj) == true)
{
return (true);
}
ProjNrPindex other = obj as ProjNrPindex;
if (Object.Equals(this.Pindex, other.Pindex) == false)
{
return (false);
}
if (Object.Equals(this.ProjNr, other.ProjNr) == false)
{
return (false);
}
return (true);
}
public override Int32 GetHashCode()
{
Int32 hash = 0;
hash += (this.Pindex != null) ? this.Pindex.GetHashCode() : 0;
hash += 1000 * ((this.ProjNr != null) ? this.ProjNr.GetHashCode() : 0);
return (hash);
}
}
public override bool Equals(object obj)
{
var other = obj as Einsatz;
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return this.Id.Equals(other.Id);
}
public override int GetHashCode()
{
unchecked
{
int hash = GetType().GetHashCode();
hash = (hash * 31) ^ this.Id.GetHashCode();
return hash;
}
}
}
Mappings are:
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="RestService"
namespace="RestService">
<class name="Einsatz" table="PLANUNG">
<composite-id name="Id">
<key-property name="ProjNr">
<column name="ProjNr" />
</key-property>
<key-property name="Pindex">
<column name="Pindex" />
</key-property>
</composite-id>
<property name="Knr" column="Knr" />
<property name="AdrNr" column="AdrNr" />
<property name="RessNr" column="RessNr" />
<property name="EndeIst" column="EndeIst" />
<property name="StartIst" column="StartIst" />
<property name="ArbeitsbeginnIst" column="ArbeitsbeginnIst" />
<property name="Kennwort" column="Kennwort" />
<one-to-one name="Taetigkeit" class="Taetigkeit" property-ref="Id"/>
</class>
</hibernate-mapping>
and
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="RestService"
namespace="RestService">
<class name="Taetigkeit" table="PLANBER">
<composite-id name="Id">
<key-property name="ProjNr">
<column name="ProjNr" />
</key-property>
<key-property name="Pindex">
<column name="Pindex" />
</key-property>
</composite-id>
<property name="RessNr" column="RessNr" />
<property name="Text" column="Text" />
<one-to-one name="Einsatz" class="Einsatz" property-ref="Id"/>
</class>
</hibernate-mapping>
The code:
var q = s.CreateQuery("from Einsatz e").List<Einsatz>();
gives me:
Error performing LoadByUniqueKey[SQL: SQL not available]
"The given key was not present in the dictionary."
I am afraid I am doing something horribly wrong but I don't know what. I might add that the database in sql server has no foreign keys so the data is not quite coherent.
your equals method is flawed. it will return false when the other object it gets is not Einsatz which should be ProjNrPindex change it to the much easier implementation:
public override bool Equals(object obj)
{
var other = obj as ProjNrPindex;
return other != null &&
Pindex == other.Pindex &&
ProjNr == other.ProjNr;
}
Also Gethashcode will throw Overflowexception in certain situations use unchecked
public override Int32 GetHashCode()
{
unchecked
{
return Pindex.GetOrDefault().GetHashCode() +
1000 * ((this.ProjNr != null) ? this.ProjNr.GetHashCode() : 0);
}
}

Best way to implement Entity with translatable properties in NHibernate

Consider the following class (simplified in order to focus in the core problem):
public class Question
{
public virtual string QuestionId { get; set; }
public virtual string Text { get; set; }
public virtual string Hint { get; set; }
}
and tables:
Question
- QuestionId ((primary key, identity column and key)
- Code
QuestionTranslation
- QuestionTranslationId (primary key, identity column; not really relevant to the association)
- QuestionId (composite key element 1)
- CultureName (composite key element 2) (sample value: en-US, en-CA, es-ES)
- Text
- Hint
How I can map the Question class so the Text and Hint properties are populated using the current thread's culture. If the thread's culture is changed I would like the Text and Hint properties to automatically return the appropriate value without the need for the Question entity to be reloaded.
Note that I'm only outlining the relevant class and properties from the business side. I'm totally open to any new class or property needed to achieve the desired functionality.
An alternative to Firo's answer (yes, I copied it and adapted it and feel bad about this).
It uses a dictionary and maps the translations as composite element (so it doesn't need the id at all)
public class Question
{
public virtual string QuestionId { get; set; }
public virtual string Text
{
get
{
var translation = Translations[CultureInfo.CurrentCulture.Name];
if (translation != null) return translation.Text
return null;
}
set
{
GetTranslation(CultureInfo.CurrentCulture.Name).Text = value;
}
}
public virtual string Hint
{
get
{
var translation = Translations[CultureInfo.CurrentCulture.Name];
if (translation != null) return translation.Hint
return null;
}
set
{
GetTranslation(CultureInfo.CurrentCulture.Name).Hint = value;
}
}
private QuestionTranslation GetTranslation(CultureInfo.CurrentCulture.Name)
{
QuestionTranslation translation;
if (!Translations.TryGetValue(CultureInfo.CurrentCulture.Name, out translation))
{
translation = new QuestionTranslation()
Translations[CultureInfo.CurrentCulture.Name] = translation;
}
return translation;
}
protected virtual IDictionary<string, QuestionTranslation> Translations { get; private set; }
}
class QuestionTranslation
{
// no id, culture name
public virtual string Text { get; set; }
public virtual string Hint { get; set; }
}
mapping:
<class name="Question">
<id name="QuestionId" column="QuestionId"/>
<map name="Translations" table="QuestionTranslation" lazy="true">
<key column="QuestionId"/>
<index column="CultureName"/>
<composite-element class="QuestionTranslation">
<property name="Text"/>
<property name="Hint"/>
</composite-element>
</bag>
</class>
Edited to reflect changed answer:
public class Question
{
public virtual string QuestionId { get; set; }
public virtual string Text
{
get
{
var currentculture = CultureInfo.CurrentCulture.Name;
return Translations
.Where(trans => trans.CultureName == currentculture)
.Select(trans => trans.Text)
.FirstOrDefault();
}
set
{
var currentculture = CultureInfo.CurrentCulture.Name;
var translation = Translations
.Where(trans => trans.CultureName == currentculture)
.FirstOrDefault();
if (translation == null)
{
translation = new QuestionTranslation();
Translations.Add(translation);
}
translation.Text = value;
}
}
public virtual string Hint
{
get
{
var currentculture = CultureInfo.CurrentCulture.Name;
return Translations
.Where(trans => trans.CultureName == currentculture)
.Select(trans => trans.Hint)
.FirstOrDefault();
}
set
{
var currentculture = CultureInfo.CurrentCulture.Name;
var translation = Translations
.Where(trans => trans.CultureName == currentculture)
.FirstOrDefault();
if (translation == null)
{
translation = new QuestionTranslation();
Translations.Add(translation);
}
translation.Hint = value;
}
}
protected virtual ICollection<QuestionTranslation> Translations { get; set; }
}
class QuestionTranslation
{
public virtual int Id { get; protected set; }
public virtual string CultureName { get; set; }
public virtual string Text { get; set; }
public virtual string Hint { get; set; }
}
<class name="Question" xmlns="urn:nhibernate-mapping-2.2">
<id name="QuestionId" column="QuestionId"/>
<bag name="Translations" table="QuestionTranslation" lazy="true">
<key>
<column name="QuestionId"/>
</key>
<one-to-many class="QuestionTranslation"/>
</bag>
</class>
<class name="QuestionTranslation" table="QuestionTranslation" xmlns="urn:nhibernate-mapping-2.2">
<id name="QuestionTranslationId"/>
<many-to-one name="ParentQuestion" column="QuestionId"/>
</class>
if you have a lot of translations then change ICollection<QuestionTranslation> Translations { get; set; } to IDictionary<string, QuestionTranslation> Translations { get; set; } and map as <map> but normally the above should do it

NHibernate cascading save

This is trying to insert null into Comment.BlogArticleID.
The following GenericADOException appeared:
"could not insert: [NHibernate__OneToMany.BO.Comment][SQL: INSERT INTO Comment (Name) VALUES (?); select SCOPE_IDENTITY()]"
The following Inner-Exception appeared:
"Cannot insert the value NULL into column 'BlogArticleID', table 'Relationships_Test_OneToMany.dbo.Comment'; column does not allow nulls. INSERT fails.\r\nThe statement has been terminated."
I need a unidirectional mapping. The answer provided yet is talking about bi-directional mapping.
Does NHibernate cascade save works with native ID generator?
DB tables:
BlogArticle{ID, Name}, where in case of ID, Identitity=true.
Comment{ID, Name, BlogArticleID}, where in case of ID, Identitity=true.
Comment.hbm.xml
<hibernate-mapping
xmlns="urn:nhibernate-mapping-2.2"
assembly="NHibernate__OneToMany.BO"
namespace="NHibernate__OneToMany.BO"
default-access="property">
<class name="Comment" table="Comment">
<id name="ID">
<generator class="native" />
</id>
<property name="Name" />
</class>
</hibernate-mapping>
public class Comment
{
private int _id;
public virtual int ID
{
get { return _id; }
set { _id = value; }
}
public Comment()
{
}
public Comment(string name)
{
this._name = name;
}
private string _name;
public virtual string Name
{
get { return _name; }
set { _name = value; }
}
}
BlogArticle.hbm.xml
<hibernate-mapping
xmlns="urn:nhibernate-mapping-2.2"
namespace="NHibernate__OneToMany.BO"
assembly="NHibernate__OneToMany.BO"
default-access="property">
<class name="BlogArticle" table="BlogArticle">
<id name="ID">
<generator class="native" />
</id>
<property name="Name" column="Name" />
<bag name="Comments" cascade="all" >
<key column="BlogArticleID" />
<one-to-many class="Comment" />
</bag>
</class>
</hibernate-mapping>
public class BlogArticle
{
private int _id;
public virtual int ID
{
get { return _id; }
set { _id = value; }
}
private string _name;
public virtual string Name
{
get { return _name; }
set { _name = value; }
}
private IList _depts;
public virtual IList Comments
{
get { return _depts; }
set { _depts = value; }
}
}
Main
class Program
{
static void Main(string[] args)
{
BlogArticle ba = new BlogArticle();
ba.Name = "Humanity";
ba.Comments = new List<Comment>();
ba.Comments.Add(new Comment("Comm1"));
ba.Comments.Add(new Comment("Comm2"));
ba.Comments.Add(new Comment("Comm3"));
Repository<BlogArticle> rep = new Repository<BlogArticle>();
rep.Save(ba);
}
}
Repository
public class Repository<T> : IRepository<T>
{
ISession _session;
public Repository()
{
_session = SessionFactoryManager.SessionFactory.OpenSession();
}
private void Commit()
{
if (_session.Transaction.IsActive)
{
_session.Transaction.Commit();
}
}
private void Rollback()
{
if (_session.Transaction.IsActive)
{
_session.Transaction.Rollback();
//_session.Clear();
}
}
private void BeginTransaction()
{
_session.BeginTransaction();
}
public void Save(T obj)
{
try
{
this.BeginTransaction();
_session.Save(obj);
this.Commit();
}
catch (Exception ex)
{
this.Rollback();
throw ex;
}
}
void IRepository<T>.Save(IList<T> objs)
{
try
{
this.BeginTransaction();
for (Int32 I = 0; I < objs.Count; ++I)
{
_session.Save(objs[I]);
}
this.Commit();
}
catch (Exception ex)
{
this.Rollback();
throw ex;
}
}
void IRepository<T>.Update(T obj)
{
try
{
this.BeginTransaction();
_session.Update(obj);
this.Commit();
}
catch (Exception ex)
{
this.Rollback();
throw ex;
}
}
void IRepository<T>.Update(IList<T> objs)
{
try
{
this.BeginTransaction();
for (Int32 I = 0; I < objs.Count; ++I)
{
_session.Update(objs[I]);
}
this.Commit();
}
catch (Exception ex)
{
this.Rollback();
throw ex;
}
}
void IRepository<T>.Delete(T obj)
{
try
{
this.BeginTransaction();
_session.Delete(obj);
this.Commit();
}
catch (Exception ex)
{
this.Rollback();
throw ex;
}
}
void IRepository<T>.Delete(IList<T> objs)
{
try
{
this.BeginTransaction();
for (Int32 I = 0; I < objs.Count; ++I)
{
_session.Delete(objs[I]);
}
this.Commit();
}
catch (Exception ex)
{
this.Rollback();
throw ex;
}
}
T IRepository<T>.Load<T>(object id)
{
return _session.Load<T>(id);
}
public IList<T> Get<T>(int pageIndex, int pageSize)
{
ICriteria criteria = _session.CreateCriteria(typeof(T));
criteria.SetFirstResult(pageIndex * pageSize);
if (pageSize > 0)
{
criteria.SetMaxResults(pageSize);
}
return criteria.List<T>();
}
public T Get<T>(object id)
{
return _session.Get<T>(id);
}
public IList<T> Get<T>()
{
return Get<T>(0, 0);
}
public IList<T> Get<T>(string propertyName, bool Ascending)
{
Order cr1 = new Order(propertyName, Ascending);
IList<T> objsResult = _session.CreateCriteria(typeof(T)).AddOrder(cr1).List<T>();
return objsResult;
}
public IList<T> Find<T>(IList<string> strs)
{
System.Collections.Generic.IList<NHibernate.Criterion.ICriterion> objs = new System.Collections.Generic.List<ICriterion>();
foreach (string s in strs)
{
NHibernate.Criterion.ICriterion cr1 = NHibernate.Criterion.Expression.Sql(s);
objs.Add(cr1);
}
ICriteria criteria = _session.CreateCriteria(typeof(T));
foreach (ICriterion rest in objs)
_session.CreateCriteria(typeof(T)).Add(rest);
criteria.SetFirstResult(0);
return criteria.List<T>();
}
public void Detach(T item)
{
_session.Evict(item);
}
}
The key column of the associated class (Comment.BlogArticleID) must be nullable in the database. NHibernate will insert rows leaving this column NULL and then perform an update to set the key.
Adding not-null="true" to the key element would not work, as this attribute is only used by the schema export tool.
Note that the failing insert includes a select for the generated identity for the new child row.
you haven't mapped the Article to the Comment:
<hibernate-mapping
xmlns="urn:nhibernate-mapping-2.2"
assembly="NHibernate__OneToMany.BO"
namespace="NHibernate__OneToMany.BO"
default-access="property">
<class name="Comment" table="Comment">
<id name="ID">
<generator class="native" />
</id>
<property name="Name" />
<many-to-one name="BlogArticle" column="BlogArticleID" /> <----------
</class>
</hibernate-mapping>
public class Comment
{
private int _id;
public virtual int ID
{
get { return _id; }
set { _id = value; }
}
public Comment() { }
public Comment(int id, string name, BlogArticle article) <------------
{
this._id = id;
this._name = name;
this._blogArticle = article; <------------
}
private string _name;
public virtual string Name
{
get { return _name; }
set { _name = value; }
}
private BlogArticle _blogArticle; <------------
public virtual BlogArticle Name <------------
{
get { return _blogArticle; } <------------
set { _blogArticle= value; } <------------
}
}