I've created an EntityFactory that creates a dynamic proxy for the
given type passed to the factory:
var person = new EntityFactory().CreateEntity<Person>();
Under the hood, I'm using LinFu to create the proxy, defining an
interceptor and implementing an interface (IStateful) on the fly:
public IStateful CreateEntity(object entity)
{
// Creates a new proxy interceptor
var statefulEntityProxy = new
StatefulEntityInterceptor(entity);
// Generate a proxy, with the stateful entity interceptor
as the interceptor, and the entity type as the
// derrived type
return (IStateful)factory.CreateProxy(entity.GetType(),
statefulEntityProxy, typeof(IStateful));
}
When I instantiate the entity using the EntityFactory, my entities now
implement IStateful and the world is good.
I then created an NHibernate interceptor so that NHibernate creates
entities via the EntityFactory as well:
public class StatefulNHibernateInterceptor : EmptyInterceptor
{
public ISessionFactory SessionFactory { set; get; }
public override object Instantiate(string clazz, EntityMode
entityMode, object id)
{
Type type = Type.GetType(clazz);
// Create a new instance of the entity using the persister
of the entity
object entity =
((ISessionFactoryImplementor)SessionFactory).GetEntityPersister(clazz).Instantiate(id,
entityMode);
// Create a proxy from the entity
object proxy = new
StatefullEntityProxyFactory().InstantiateEntityProxy(entity);
return proxy;
}
/// <summary>
/// Gets the entity name
/// </summary>
/// <remarks>Because the entity is actually a proxy, we must
return the base type of the entity, which is the actual entity type</
remarks>
public override string GetEntityName(object entity)
{
return entity.GetType().BaseType.FullName;
}
}
And then I configured NHibernate (using Fluent NHibernate) to use the
interceptor:
...
var interceptor = new StatefulNHibernateInterceptor();
configuration = Fluently.Configure()
.Database(FluentNHibernate.Cfg.Db.MsSqlConfiguration.MsSql2005
.Dialect<NHibernate.Dialect.MsSql2005Dialect>()
.Driver<SqlClientDriver>()
.ConnectionString(connectionString)
.ShowSql()
.ProxyFactoryFactory<ProxyFactoryFactory>()
.QuerySubstitutions("true 1, false 0, yes 'Y', no
'N'"))
.Mappings((m =>
m.FluentMappings.AddFromAssembly(typeof(TClassFromMappingAssembly).Assembly)))
.BuildConfiguration().SetNamingStrategy(NHibernate.Cfg.ImprovedNamingStrategy.Instance)
.SetInterceptor(interceptor);
sessionFactory = configuration.BuildSessionFactory();
interceptor.SessionFactory = sessionFactory;
...
I thought my configurations were complete, but my tests continue to
fail and I don't know why.
[Test]
public void Add_ProxyUsed_RepositoryContainsNewItem()
{
var repository = new PersonRepository(UnitOfWork);
var person = new EntityFactory().CreateEntity<Person>();
person.Name = "PersonName";
repository.Add(person); // The test fails HERE
//some assertions here
}
The test fails when I try to add the person to the PersonRepository,
throwing the following exception:
NHibernate.HibernateException : identifier of an instance of ...
Person was altered from db6e6327-9d4e-4c7d- 822d-9e3a0106cafc to
00000000-0000-0000-0000-000000000000
The Add method of the person repository is doing a very straight-
forward INSERT as follows:
session.Save(person);
And the mapping of the person object is also pretty simple (also using
Fluent NHibernate):
public PersonMap()
{
Table("Person");
Id(x => x.Id)
.GeneratedBy.GuidComb();
Map(x => x.Name)
.Length(256)
.Not.Nullable()
.UniqueKey("Name");
Map(x => x.LoweredName)
.Length(256)
.Not.Nullable()
.UniqueKey("LoweredName").Access.ReadOnlyPropertyThroughCamelCaseField(Prefix.Underscore);
Map(x => x.Description)
.Nullable().Length(10000);
}
I am not modifying the Id of any entity directly, so I believe that
NHibernate is updating the Id of the person object and, when the
entity is flushed and the Id is validated in NHibernate, the exception
is then being thrown.
If I remove the dynamic proxies altogether, my tests pass and my
entities persist successfully.
Am I missing some configuration in order to get entity proxies working
in NHibernate? Any ideas on why I'm receiving this error? Any help
would be GREATLY appreciated. Thanks!
--
You received this message because you are subscribed to the Google Groups
"nhusers" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/nhusers?hl=en.