Oren Eini

CEO of RavenDB

a NoSQL Open Source Document Database

Get in touch with me:

oren@ravendb.net +972 52-548-6969

Posts: 7,584
|
Comments: 51,218
Privacy Policy · Terms
filter by tags archive
time to read 1 min | 171 words

Shawn Wildermuth has bridged the gap between the two, implementing IUpdatable on top of Linq to NHibernate. This means that you can now expose your NHibernate domain model as a set of REST services.

This functionality is now included with Linq for NHibernate. Thanks Shawn!

There is a live sample here: http://www.silverlightdata.com/Simple/NHibernate.aspx

Or you can hit the URLs directly and see what kind of formatting it has:

From a technological perspective, I think this is awesome. However, there are architectural issues with exposing your model in such a fashion. Specifically, with regards to availability and scalability on the operations side, and schema versioning and adaptability on the development side.

ADO.Net Data Services are a very thin wrapper around a DB, and as such, they should be treated as such. Do not expose them where you wouldn't want to expose your DB as well.

time to read 1 min | 182 words

On the face of it, this is a nonsense post. What do I mean, integrating NHibernate and Active Record? Active Record is based on NHibernate, after all. What kind of integration you need? Well, sometimes you want to be able to use NHibernate entities in an Active Record project. And that tended to be very hard. (The other way was extremely easy, just tell Active Record to generate the mapping and move from there.)

A week or so ago I added support for doing it the other way around, of adding POCO NHibernate entities into the ActiveRecord model.

Here is the test:

[Test]
public void CanIntegrateNHibernateAndActiveRecord()
{
	ActiveRecordStarter.ModelsValidated += delegate
	{
		new ActiveRecordModelBuilder().CreateDummyModelFor(typeof(NHibernateClass));
	};
	ActiveRecordStarter.Initialize(
		GetConfigSource(),
		typeof(ActiveRecordClass),
		typeof(NHibernateClass));

	Recreate();

	using (TransactionScope tx = new TransactionScope())
	{
		ActiveRecordClass ar = new ActiveRecordClass();
		ar.Friend = new NHibernateClass();
		ActiveRecordMediator.Save(ar.Friend);
		ActiveRecordMediator.Save(ar);
		tx.VoteCommit();
	}

	using (TransactionScope tx = new TransactionScope())
	{
		ActiveRecordClass first = ActiveRecordMediator<ActiveRecordClass>.FindFirst();
		Assert.IsNotNull(first);
		Assert.IsNotNull(first.Friend);
	}
}

Note that I would reserve this to advance scenarios only, in most cases, it is recommended to only use a consistent approach.

time to read 2 min | 390 words

Rhino Security is a good example of a pluggable domain model, in which we can plug some functionality into different and varied domains.

Here is an interesting demo to show how you can use it.

public static void DemoUsingCustomerCareModule<TCustomer>(string schema)
    where TCustomer : ICustomer, new()
{
    Configuration cfg = new Configuration()
        .Configure("hibernate.cfg.xml")
        .AddAssembly(typeof(Lead).Assembly)
        .AddAssembly(typeof(TCustomer).Assembly);

    cfg.MapManyToOne<ICustomer, TCustomer>();
    cfg.SetSchema(schema);

    new SchemaExport(cfg).Execute(true, true, false, true);

    ISessionFactory factory = cfg.BuildSessionFactory();

    object accountCustomerId;
    using (var session = factory.OpenSession())
    using (var tx = session.BeginTransaction())
    {
        var customer = new TCustomer { Name = "ayende"};
        session.Save(customer);
        var customerCareService = new CustomerCareService(session);
        customerCareService.GenerateLeadFor(customer, "phone call");
        customerCareService.GenerateLeadFor(customer, "email ");
        tx.Commit();

        accountCustomerId = session.GetIdentifier(customer);
    }

    using (var session = factory.OpenSession())
    using (var tx = session.BeginTransaction())
    {
        var customer = session.Get<TCustomer>(accountCustomerId);
        var customerCareService = new CustomerCareService(session);

        Console.WriteLine("Leads for: " + customer.Name);
        foreach (var lead in customerCareService.GetLeadsFor(customer))
        {
            Console.WriteLine("\t" + lead.Note);
        }

        tx.Commit();
    }
}

This can be used with:

DemoUsingCustomerCareModule<AccountingCustomer>("Accounting");

DemoUsingCustomerCareModule<HelpDeskCustomer>("HelpDesk");
time to read 5 min | 852 words

A while ago I posted how to handle dynamic mapping with Active Record, it was incredibly easy to do, because Active Record has a lot of smarts internally, and output the XML, on top of which NHibernate adds quite a bit of convention over configuration as well. Doing the same using NHibernate directly is possible, but a bit long winded. Here is the sample code, which link all the Employee properties to the correct entity:

Configuration cfg = new Configuration()
    .AddAssembly(typeof (Employee).Assembly)
    .AddAssembly(typeof(ScheduledTask).Assembly);
Mappings mappings = cfg.CreateMappings();
foreach (PersistentClass persistentClass in mappings.Classes)
{
    if (persistentClass.MappedClass.GetProperty("Employee") == null)
        continue;
    Property prop = new Property();
    PersistentClass employeeClass = cfg.GetClassMapping(typeof (Employee));
    Table table = employeeClass.Table;
    ManyToOne value = new ManyToOne(table);
    value.ReferencedEntityName = typeof (Employee).FullName;
    Column column = new Column("Employee");
    value.AddColumn(column);
    prop.Value = value;
    prop.Name = "Employee";
    prop.PersistentClass = employeeClass;
    persistentClass.AddProperty(prop);
    persistentClass.Table.AddColumn(column);
    persistentClass.Table.CreateForeignKey("FK_EmployeeTo" + persistentClass.MappedClass.Name,
                                           new Column[] {column,}, typeof (Employee).FullName);
}
cfg.BuildSessionFactory();
new SchemaExport(cfg).Execute(true, true, false, true);

As you can see, there is a lot that needs to be done, we have to tell NHibernate a lot of things it would generally be able to figure out on its own. We can shove this to an extension method and get really nice syntax:

public static void MapManyToOne<TEntityInterface, TEntity>(this Configuration cfg)
{
    Mappings mappings = cfg.CreateMappings();
    foreach (PersistentClass persistentClass in mappings.Classes)
    {
        var propertyNames = new List<string>();
        foreach (PropertyInfo property in persistentClass.MappedClass.GetProperties())
        {
            if (property.PropertyType == typeof (TEntityInterface))
            {
                propertyNames.Add(property.Name);
            }
        }
        if (propertyNames.Count == 0)
            continue; 

        var prop = new Property();
        PersistentClass targetClass = cfg.GetClassMapping(typeof (TEntity)); 

        foreach (string propertyName in propertyNames)
        {
            Table table = targetClass.Table;
            var value = new ManyToOne(table);
            value.ReferencedEntityName = typeof (TEntity).FullName;
            var column = new Column(propertyName);
            value.AddColumn(column);
            prop.Value = value;
            prop.Name = propertyName;
            prop.PersistentClass = targetClass;
            persistentClass.AddProperty(prop);
            persistentClass.Table.AddColumn(column);
            string fkName = string.Format("FK_{0}To{1}", propertyName, persistentClass.MappedClass.Name);
            persistentClass.Table.CreateForeignKey(fkName,
                                                   new[] {column,}, typeof (TEntity).FullName);
        }
    }
}

Now we can use this with the following syntax:

cfg.MapManyToOne<IEmployee, Employee>();

Which is much nicer.

time to read 1 min | 80 words

With the advent of the NHibernate Users list, we also needed a place for frequent questions. While the Hibernate's site already has a FAQ in place, I feel that a blog is a better medium for this.

Therefor, welcome the NHibernate FAQ Blog, which Gabriel Schenker and Tom Opgenorth has agreed to maintained. There are several good articles there already. Covering anything from setting up query logging to correct handling of entity equality.

Subscribed.

time to read 9 min | 1710 words

image

It gives me great pleasure to announce that NHiberante 2.0 Alpha 1 was released last night and can be downloaded from this location.

We call this alpha, but many of us are using this in production, so we are really certain in its stability. The reason that this is an alpha is that we have made a lot of changes in the last nine months (since the last release), and we want to get more real world experience before we ship this. Recent estimates are of about 100,000 lines of code has changed since the last release.

You can see the unofficial change list below. Please note that there are breaking changes in the move to NHibernate 2.0. There are also significant improvement in many fields, as you will see in a moment.

We are particularly interested in hearing about compatibility issues, performance issues and "why doesn't this drat work?" issues.

We offer support for moving to NHibernate 2.0 Alpha on the NHibernate mailing list at: nhusers@googlegroups.com (http://groups.google.com/group/nhusers).

And now, for the changes:

  • New features:
    • Add join mapping element to map one class to several tables
    • <union> tables and <union-subclass> inheritance strategy
    • HQL functions 'current_timestamp', 'str' and 'locate' for PostgreSQL dialect
    • VetoInterceptor - Cancel Calls to Delete, Update, Insert via the IInterceptor Interface
    • Using constants in select clause of HQL
    • Added [ Table per subclass, using a discriminator ] Support to Nhibernate
    • Added support for paging in sub queries.
    • Auto discovery of types in custom SQL queries
    • Added OnPreLoad & OnPostLoad Lifecycle Events
    • Added ThreadStaticSessionContext
    • Added <on-delete> tag to <key>
    • Added foreign-key="none" since the Parent have not-found="ignore". (not relevant to SQL Server)
    • Added DetachedQuery
    • ExecuteUpdate support for native SQL queries
    • From Hibernate:
      • Ported Actions, Events and Listeners
      • Ported StatelessSession
      • Ported CacheMode
      • Ported Statistics
      • Ported QueryPlan
      • Ported ResultSetWrapper
      • Ported  Structured/Unstructured cache
      • Ported SchemaUpdate
      • Ported Hibernate.UserTypes
      • Ported Hibernate.Mapping
      • Ported Hibernate.Type
      • Ported EntityKey
      • Ported CollectionKey
      • Ported TypedValue
      • Ported SQLExceptionConverter
      • Ported Session Context
      • Ported CascadingAction
  • Breaking changes:
    • Changed NHibernate.Expression namespace to NHibernate.Criterion
    • Changed NHiberante.Property namespace to NHiberante.Properties
    • No AutoFlush outside a transaction - Database transactions are never optional, all communication with a database has to occur inside a transaction, no matter if you read or write data.
    • <nhibernate> section is ignored, using <hibernate-configuration> section (note that they have different XML formats)
    • Configuration values are no longer prefixed by "hibernate.", if before you would specify "hibernate.dialect", now you specify just "dialect"
    • IInterceptor changed to match the Hibernate 3.2 Interceptor - interface changed
    • Will perform validation on all named queries at initialization time, and throw if any is not valid.
    • NHibernate will return long for count(*) queries on SQL Server
    • SaveOrUpdateCopy return a new instance of the entity without change the original.
    • INamingStrategy interface changed
    • NHibernate.Search - Moved Index/Store attributes to the Attributes namespace
    • Changes to IType, IEntityPersister, IVersionType - of interest only to people who did crazy stuff with NHibernate.
    • <formula> must contain parenthesis when needed
    • IBatcher interface change
  • Fixed bugs:
    • Fixing bug with HQL queries on map with formula.
    • Fixed exception when the <idbag> has a <composite-element> inside; inside which, has a <many-to-one>
    • Multi criteria doesn't support paging on dialects that doesn't support limiting the query size using SQL.
    • Fixed an issue with limit string in MsSql2005 dialect sorting incorrectly on machines with multiple processors
    • Fixed an issue with getting NullReferenceException when using SimpleSubqueryExpression within another subexpression
    • Fixed Null Reference Exception when deleting a <list> that has holes in it.
    • Fixed duplicate column name on complex joins of similar tables
    • Fixed MultiQuery force to use parameter in all queries
    • Fixed concat function fails when a parameter contains a comma, and using MaxResults
    • Fixed failure with Formula when using the paging on MSSQL 2005 dialect
    • Fixed PersistentEnumType incorrectly assumes enum types have zero-value defined
    • Fixed SetMaxResults() returns one less row when SetFirstResult() is not used
    • Fixed Bug in GetLimitString for SQL Server 2005 when ordering by aggregates
    • Fixed SessionImpl.EnableFilter returns wrong filter if already enabled
    • Fixed Generated Id does not work for MySQL
    • Fixed one-to-one can never be lazy
    • Fixed FOR UPDATE statements not generated for pessimistic locking
  • Improvements:
    • Added Guid support for Postgre Dialect
    • Added support for comments in queries
    • Added Merge and Persist to ISession
    • Support IFF for SQL Server
    • IdBag now work with Identity columns
    • Multi Criteria now uses the Result Transformer
    • Handling key-many-to-one && not-found
    • Can now specify that a class is abstract in the mapping.
  • Guidance:
    • Prefer to use the Restrictions instead of the Expression class for defining Criteria queries.
  • Child projects:
    • Added NHibernate.Validator
    • Added NHibernate.Shards
    • NHibernate.Search updated match to Hibernate Search 3.0
  • Criteria API:
    • Allow Inspection, Traversal, Cloning and Transformation for ICriteria and DetachedCriteria
      • Introduced CriteriaTransformer class
      • GetCriteriaByPath, GetCriteriaByAlias
    • Added DetachedCriteria.For<T>
    • Added Multi Criteria
    • Projections can now pass parameters to the generated SQL statement.
    • Added support for calling Sql Functions (HQL concept) from projections (Criteria).
    • Added ConstantProjection
    • Added CastProjection
    • Can use IProjection as a parameter to ICriterion
  • Better validation for proxies:
    • Now supports checking for internal fields as well
    • Updated Castle.DynamicProxy2.dll to have better support for .NET 2.0 SP1
  • SQL Lite:
    • Support for multi query and multi criteria
    • Supporting subselects and limits
    • Allowed DROP TABLE IF EXISTS semantics
  • PostgreSQL (Npgsql):
    • Enable Multi Query support for PostgreSQL
  • FireBird:
    • Much better overall support
  • Batching:
    • Changed logging to make it clearer that all commands are send to the database in a single batch.
    • AbstractBatcher now use the Interceptor to allow the user intercept and change an SQL before it's preparation
  • Error handling:
    • Better error message on exception in getting values in Int32Type
    • Better error message when using a subquery that contains a reference to non existing property
    • Throws a more meaningful exception when calling UniqueResult<T>() with a value type and the query returns null.
    • Overall better error handling
    • Better debug logs
  • Refactoring:
    • Major refactoring internally to use generic collections instead of the non generic types.
    • Major refactoring to the configuration and the parsing of hbm files.
  • Factories:
    • Added ProxyFactoryFactory
    • Added BatchingBatcherFactory
time to read 4 min | 645 words

Udi Dahan has been talking about this for a while now. As usual, he makes sense, but I am working in different enough context that it takes time to assimilate it.

At any rate, we have been talking about this for a few days, and I finally sat down and decided that I really need to look at it with code. The result of that experiment is that I like this approach, but am still not 100% sold.

The first idea is that we need to decouple the service layer from our domain implementation. But why? The domain layer is under the service layer, after all. Surely the service layer should be able to reference the domain. The reasoning here is that the domain model play several different roles in most applications. It is the preferred way to access our persistent information (but they should not be aware of persistence), it is the central place for business logic, it is the representation of our notions about the domain, and much more that I am probably leaving aside.

The problem here is there is a dissonance between the requirements we have here. Let us take a simple example of an Order entity.

image As you can see, Order has several things that I can do. It can accept an new line, and it can calculate the total cost of the order.

But those are two distinct responsibilities that are based on the same entity. What is more, they have completely different persistence related requirements.

I talked about this issue here, over a year ago.

So, we need to split the responsibilities, so we can take care of each of them independently. But it doesn't make sense to split the Order entity, so instead we will introduce purpose driven interfaces. Now, when we want to talk about the domain, we can view certain aspect of the Order entity in isolation.

This leads us to the following design:

image

And now we can refer to the separate responsibilities independently. Doing this based on the type open up to the non invasive API approaches that I talked about before. You can read Udi's posts about it to learn more about the concepts. Right now I am more interested in discussing the implementation.

First, the unit of abstraction that we work in is the IRepository<T>, as always.

The major change with introducing the idea of a ConcreteType to the repository. Now it will try to use the ConcreteType instead of the give typeof(T) that it was created with. This affects all queries done with the repository (of course, if you don't specify ConcreteType, nothing changes).

The repository got a single new method:

T Create();

This allows you to create new instances of the entity without knowing its concrete type. And that is basically it.

Well, not really :-)

I introduced two other concepts as well.

public interface IFetchingStrategy<T>
{
	ICriteria Apply(ICriteria criteria);
}

IFetchingStrategy can interfere in the way queries are constructed. As a simple example, you could build a strategy that force eager load of the OrderLines collection when the IOrderCostCalculator is being queried.

There is not complex configuration involved in setting up IFetchingStrategy. All you need to do is register your strategies in the container, and let the repository do the rest.

However, doesn't this mean that we now need to explicitly register repositories for all our entities (and for all their interfaces)?

Well, yes, but no. Technically we need to do that. But we have help, EntitiesToRepositories.Register, so we can just put the following line somewhere in the application startup and we are done.

EntitiesToRepositories.Register(
	IoC.Container, 
	UnitOfWork.CurrentSession.SessionFactory, 
	typeof (NHRepository<>),
	typeof (IOrderCostCalculator).Assembly);

And this is it, you can start working with this new paradigm with no extra steps.

As a side benefit, this really pave the way to complex multi tenant applications.

time to read 1 min | 89 words

I am working on ICriterion and IProjection at the moment, making each understand each other. It is working very well, and I really like the ability to just go in and make a drastic change.

The problem is the scope of the change. I have had to touch pretty much all of the NHibernate.Expression in the last two days. Just to give you an idea, here is the most recent comment.

Damn I am glad that I have tests there.

image

FUTURE POSTS

No future posts left, oh my!

RECENT SERIES

  1. Production postmorterm (2):
    11 Jun 2025 - The rookie server's untimely promotion
  2. Webinar (7):
    05 Jun 2025 - Think inside the database
  3. Recording (16):
    29 May 2025 - RavenDB's Upcoming Optimizations Deep Dive
  4. RavenDB News (2):
    02 May 2025 - May 2025
  5. Production Postmortem (52):
    07 Apr 2025 - The race condition in the interlock
View all series

Syndication

Main feed ... ...
Comments feed   ... ...
}