Hello,
I have a Person class that has (via composition) a set of Addresses. I'm surprised by the SQL generated by the following scenario: create and persist one Person, load all Persons, create and persist another Person. It seems that saving the second Person triggers an update on the first Person.
My version of NHibernate is 3.1.0.4000.
The mapping:
Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="NHib"
namespace="NHib"
>
<class name="Person">
<id name="Id">
<generator class="guid" />
</id>
<version name="Version" column="version" />
<property name="Name" />
<set name="Address" lazy ="true">
<key column="id" />
<composite-element class="Address">
<property name="Number" />
<property name="Street" />
</composite-element>
</set>
</class>
</hibernate-mapping>
...and the code:
Code:
class Address
{
public int Number { get; set; }
public string Street { get; set; }
}
class Person
{
public virtual Guid Id { get; set; }
public virtual int Version { get; set; }
public virtual string Name { get; set; }
public virtual ICollection<Address> Address { get; set; }
}
class Program
{
static void Main(string[] args)
{
System.Console.SetOut(new DebugTextWriter());
var cfg = new Configuration();
cfg.Configure();
cfg.AddAssembly(typeof(Person).Assembly);
var sessionFactory = cfg.BuildSessionFactory();
using (var session = sessionFactory.OpenSession())
{
new SchemaExport(cfg).Execute(false, true, false, session.Connection, Console.Out);
var god = new Person()
{
Name = "God",
Address = new List<Address>()
{
new Address() { Number = 1, Street = "Heavens"},
}
};
using (var transaction = session.BeginTransaction())
{
session.Save(god);
transaction.Commit(); // 1
}
var persons = session.CreateCriteria<Person>().List(); // 2
var devil = new Person()
{
Name = "Devil",
Address = new List<Address>()
{
new Address() { Number = 1, Street = "Hell"},
}
};
using (var transaction = session.BeginTransaction())
{
session.Save(devil);
transaction.Commit(); // 3
}
}
}
}
In the first commit (marked //1) the generated SQL is:
Code:
NHibernate: INSERT INTO Person (version, Name, Id) VALUES (@p0, @p1, @p2);@p0 = 1 [Type: Int32 (0)], @p1 = 'God' [Type: String (0)], @p2 = 30c30ca0-6637-490a-a1fd-32f8044bafb4 [Type: Guid (0)]
NHibernate: UPDATE Person SET version = @p0, Name = @p1 WHERE Id = @p2 AND version = @p3;@p0 = 2 [Type: Int32 (0)], @p1 = 'God' [Type: String (0)], @p2 = 30c30ca0-6637-490a-a1fd-32f8044bafb4 [Type: Guid (0)], @p3 = 1 [Type: Int32 (0)]
NHibernate: INSERT INTO Address (id, Number, Street) VALUES (@p0, @p1, @p2);@p0 = 30c30ca0-6637-490a-a1fd-32f8044bafb4 [Type: Guid (0)], @p1 = 1 [Type: Int32 (0)], @p2 = 'Heavens' [Type: String (0)]
NHibernate: SELECT this_.Id as Id0_0_, this_.version as version0_0_, this_.Name as Name0_0_ FROM Person this_
I pretty much agree with it, although it looks like the UPDATE could be spared.
Same when loading all the Persons (//2):
Code:
NHibernate: SELECT this_.Id as Id0_0_, this_.version as version0_0_, this_.Name as Name0_0_ FROM Person this_
However, on the second commit (//3) I see:
Code:
NHibernate: INSERT INTO Person (version, Name, Id) VALUES (@p0, @p1, @p2);@p0 = 1 [Type: Int32 (0)], @p1 = 'Devil' [Type: String (0)], @p2 = d1834ca4-fa13-441d-b68c-1d832ffc0694 [Type: Guid (0)]
NHibernate: UPDATE Person SET version = @p0, Name = @p1 WHERE Id = @p2 AND version = @p3;@p0 = 3 [Type: Int32 (0)], @p1 = 'God' [Type: String (0)], @p2 = 66e155c1-7131-4fbb-88de-644dbdc2530c [Type: Guid (0)], @p3 = 2 [Type: Int32 (0)]
NHibernate: UPDATE Person SET version = @p0, Name = @p1 WHERE Id = @p2 AND version = @p3;@p0 = 2 [Type: Int32 (0)], @p1 = 'Devil' [Type: String (0)], @p2 = d1834ca4-fa13-441d-b68c-1d832ffc0694 [Type: Guid (0)], @p3 = 1 [Type: Int32 (0)]
NHibernate: DELETE FROM Address WHERE id = @p0 AND Number = @p1 AND Street = @p2;@p0 = 66e155c1-7131-4fbb-88de-644dbdc2530c [Type: Guid (0)], @p1 = 1 [Type: Int32 (0)], @p2 = 'Heavens' [Type: String (0)]
NHibernate: INSERT INTO Address (id, Number, Street) VALUES (@p0, @p1, @p2);@p0 = 66e155c1-7131-4fbb-88de-644dbdc2530c [Type: Guid (0)], @p1 = 1 [Type: Int32 (0)], @p2 = 'Heavens' [Type: String (0)]
NHibernate: INSERT INTO Address (id, Number, Street) VALUES (@p0, @p1, @p2);@p0 = d1834ca4-fa13-441d-b68c-1d832ffc0694 [Type: Guid (0)], @p1 = 1 [Type: Int32 (0)], @p2 = 'Hell' [Type: String (0)]
What's the reason for this messing with the first Person ? Can it be avoided ?