Another Classification: Infrastructure Patterns


Without further ado, let's get started with type of metadata.

Metadata Mapping: Type of Metadata

In Chapter 8, I defined three different types of metadata for the Metadata Mapping pattern [Fowler PoEAA]:

  • XML document(s) or other document formats

  • Attributes

  • Source code

This category was simple regarding NHibernate because its metadata is typically XML documents. You can describe the metadata in source code as well in the works, but that's not the mainstream thing to do at all.

There are attribute-based approaches as well, but they generate metadata as XML documents.

Identity Field

I have already touched on the matter of how you deal with Identity Fields in NHibernate, but I'd like to go a little deeper. Earlier I showed how to map an Identity Field that is of the Guid type. Let's take a look at the Product Entity, which has an int for the Identity Field, and the value is generated with an IDENTITY (auto incrementing column) in the database. It could then look like this:

<id name="Id" access="field.camelcase-underscore"     unsaved-value="0" >     <generator docEmphStrong">identity" /> </id>


As I said in Chapter 8, when it comes to new entities, the values for Identity Fields can be generated in at least four different layers:

  • Consumer

  • Domain Model

  • Database

  • O/R Mapper

In the case of the guid, you can generate it in all the layers, but it's recommended that you do it in the O/R Mapper. In the example with IDENTITY just shown, the value is generated in the database, and that actually affects the programming model a lot. First, there will be a database jump earlier than you expect. Second, there might be an INSERT just to grab the IDENTITY value. Both examples are something I consider to be problems, and therefore I don't like to use IDENTITYs more than is necessary.

NHibernate Supports COMBs

As a matter of fact, Guids are often a very nice solution. But perhaps some of you have read my article about a possible cost of INSERTs when you use Guids as primary keys [Nilsson COMB]. The problem is that the INSERT throughput might be many times lower for tables with Guids for primary keys than if you use int s. That's not a problem you will typically get, but it might come and bite you if you have very large tables and a high INSERT load. I suggested a solution to the problem in the article I called "COMB." It's basically a Guid, but kind of a sequential one. I was very surprised to see that NHibernate added support for COMB in a specific alpha version. To use the COMB generator, the metadata could look like this (the only difference is that generator is guid.comb and not just guid):

<id name="Id" access="field.camelcase-underscore"     unsaved-value="00000000-0000-0000-0000-000000000000" >     <generator docEmphStrong">.comb" /> </id>



It is easiest for you if you let NHibernate generate the Guids for you, but that's not always possible, of course. Sometimes you must use assigned Identity Fields instead, which makes it quite a bit harder. For example, you can't let NHibernate determine using UPDATE or INSERT by looking at unsaved-value. Instead, you will typically tell NHibernate what to do with explicit calls to Save() or Update() instead of SaveOrUpdate().

Note

As I said earlier in this chapter, you can use the version tag+unsaved-value tag for helping you out when you prefer to set the Identity Field values on your own.


These were just a few examples of strategies for Identity Fields. NHibernate supports many more. You can also plug in your own strategies quite easily.

Foreign Key Mapping

A foreign key mapping could look like this in a mapping file; here (in the Order.hbm.xml file) it is describing that an Order has a Customer:

<many-to-one name="Customer" access="field.camelcase-underscore"      column="CustomerId" not-null="true" />


Without going into details, I would say that NHibernate has strong support for many relationship styles that will solve most of your needs in that area. It's not very easy, though, to learn to use all variations effectively, but you can go a long way with a few basic ones.

On the other hand, what is pretty easy is using the Embedded Value pattern [Fowler PoEAA] with NHibernate.

Embedded Value

NHibernate uses the word component (as if that word didn't have enough different meanings) for describing an Embedded Value. Let's repeat again what it could look like in the mapping file to describe that a Customer has an Address:

<component name="Address" access="field">     <property name="Street" access="field.camelcase-underscore"         type="AnsiString" length="50" not-null="true" />     <property name="PostalCode"         access="field.camelcase-underscore"         type="AnsiString" length="10" not-null="true" />     <property name="Town" access="field.camelcase-underscore"         type="AnsiString" length="50" not-null="true" />       <property name="Country" access="field.camelcase-underscore"         type="AnsiString" length="50" not-null="true" /> </component>


Note that the Customers table contains all columns, but the Customer class has just an Address field.

When that is in place, using the Embedded Value from the consumer is very easy to understand. It could look like this, for example:

Console.WriteLine(aCustomer.Address.Street);


Something to think about, however, is whether the Value Object Address should be immutable or not. I would probably choose immutable in this particular example, but it's not always an easy choice.

If you decide to use mutable, you could write the code like this instead of instantiating a new Address:

aCustomer.Address.Street = "Large Street 42";


Note

If you have an Embedded Value that should be used in many other classes, it could be a good idea to implement IUserType so that you don't have to describe the mapping over and over again. That's also the case if the storage is different from the type to expose. The translation is then done by the IUserType implementation.

Consequently, one downside is that the Domain Model will have to refer to nhibernate.dll, or you will have to have the specific code in a separate assembly and inherit the basic Domain Model class instead.

I try to avoid this if possible. When the ordinary approach for Embedded Value can be used, everything is just fine. For tricky cases, it's often possible to do the translation manually instead in property get/set from/to private fields and then map those private fields to the database.

A typical example of when I avoid a certain construct or deal with it with custom get/set code is when it comes to applying the typesafe enum pattern [Bloch Effective Java] (for example, for adding behavior to enums). First, I think twice if I can't just live with an ordinary C# enum. Second choice is custom get/set code so I don't have to deal with IUserType. It feels like a quite big solution for a tiny thing.

To end this note, just one more thing: Don't exaggerate your tries to avoid a reference to nhibernate.dll in your Domain Model. If the benefit is bigger than the cost...


Inheritance Solutions

NHibernate supports all three different inheritance solutions, namely Single Table Inheritance, Class Table Inheritance, and Concrete Table Inheritance [Fowler PoEAA]. If we assume that Customer and Vendor inherits from Company, the mapping information could look like this:

<discriminator column="Type" type="AnsiString" length="8"     not-null="true" />


Then, something like the following is needed for each subclass, where the specifics are described (that is, the mapping information that isn't for the Company class):

<subclass discriminator-value="Customer" name="Customer">     <property name="CustomerNumber"         access="field.camelcase-underscore"/> </subclass> <subclass discriminator-value="Vendor" name="Vendor">     <property name="VendorNumber"         access="field.camelcase-underscore"/> </subclass>


From that you understand that the only variation in each case is a single specific field, CustomerNumber and VendorNumber. In this case, we will have just a single Companies table, and it would look like this (meaning that we used Single Table Inheritance here):

create table Companies (   Id UNIQUEIDENTIFIER not null,    Type VARCHAR(8) not null,    Version INT not null,    Name VARCHAR(100) not null,    Street VARCHAR(50) not null,    PostalCode VARCHAR(10) not null,    Town VARCHAR(50) not null,    Country VARCHAR(50) not null,    CustomerNumber INT null,    VendorNumber INT null,    primary key (Id) )


That means that for Vendors, CustomerNumber will be NULL, and vice versa. The Type column will have the value "Customer" or "Vendor" (or normally some smaller symbols).

Note

I know, some of you are feeling so uncomfortable regarding this example because you prefer to use something like the Party archetype instead [Arlow/Neustadt Archetype Patterns]. Or at least you prefer not such an overuse of inheritance, if the only variation was a single field and nothing else.

My intention was just to show an obvious and clear example.


And as you would probably expect, when the inheritance mapping is in place, the consumer code can forget about how the inheritance hierarchy is actually stored and focus on how to use the inheritance hierarchy instead.

Identity Map

NHibernate uses an Identity Map on an ISession level. You can easily see this if you read an instance by Id with Load(), make a change to the row directly in the database, and then read the instance again with Load() (with the same ISession instance). You won't see the change because NHibernate didn't roundtrip to the database after the first Load(), but instead the instance was grabbed from the Identity Map.

NHibernate also uses the Identity Map when it comes to querying; not for finding instances, but for placing the Identities in the Map to support future Load() calls from the Identity Map.

If you'd like to force an instance away from the Identity Map, you can call Evict() on the ISession, or Clear() to clear the Identity Map from all instances, or of course Close() the ISession.

Unit of Work

It probably won't come as a surprise to learn that NHibernate uses the Unit of Work pattern [Fowler PoEAA] as well, and again it's dealt with in the ISession. That said, the implementation is pretty different from the most typical one. Instead of registering what has happened with the Unit of Work, NHibernate takes a snapshot of the instances when they are read from the database. At flush time, the instances known by ISession are compared to the snapshots to create a Unit of Work at that point in time.

To be clear, in a way deletes are registered and so are notifications of new instances with, for example, SaveOrUpdate().

As always, there are pros and cons to this solution, and one obvious drawback is when there are many instances to investigate, only to find that just one should be flushed. That's one reason for why Hibernate (that's right, Hibernate, not NHibernate, at least not at the time of this writing) 3 has been changed regarding this.

Lazy Load/Eager Load

If you do want to use (automatic) Lazy Load [Fowler PoEAA] with NHibernate, that's easily done. You just declare it in the metadata like this, for example:

<bag name="OrderLines" access="field.camelcase-underscore" cascade="all" lazy="true">     <key column="OrderId" />     <one-to-many docText">Now the OrderLines of an Order are lazily loaded when the OrderLines are needed for the first time. In order for this to work, however, you must have a connected ISession.

If you don't use the lazy="true" declaration in the metadata, you will effectively get Eager Load instead. NHibernate supports several different approaches for Eager Load, such as OUTER JOIN and several SELECT statements batched after each other.

What might be important is that when you do Eager Load with several SELECT statements, you might get read inconsistency (which might be a bigger problem in the case of Lazy Load) in this case, too. This can be avoided with explicit transaction control and by increasing the Transaction Isolation Level to serializable [Nilsson NED], but it's rarely a serious problem, so I won't go into details here.

You can also control in code whether you want Eager/Lazy Load. That's something you can do when you use querying, but we are satisfied with the discussion about querying we've had already in this chapter.

Controlling Concurrency

Finally, we need support for controlling concurrency. Fowler [Fowler PoEAA] describes the following solutions to the problem:

  • Coarse-Grained Lock

  • Implicit Lock

  • Optimistic Offline Lock

  • Pessimistic Offline Lock

NHibernate deals with Optimistic Offline Lock if you add a <version> tag to the entities, like this:

<version name="Version" access="field.camelcase-underscore" />


Then, if the row in the database has another value of the version column compared to what you expect it to be at persist time, someone else has updated the row, and there's a conflict in concurrency (and you'll get a StaleObjectStateException).

You'll have to deal with the other three mechanisms yourself. NHibernate doesn't support them out of the box.

Bonus: Validation Hooks

Something that wasn't discussed in Chapter 8 but that I added here as a small bonus is validation hooks. NHibernate has an IValidatable interface that will get calls by NHibernate at Flush().

But then I need to reference the nhibernate.dll in the Domain Model, so I prefer a solution like the one I used in Chapter 7, "Let the Rules Rule." I mean, I can use an IInterceptor (yet another NHibernate interface, but in this case not used by the Domain Model) implementation for checking the rules implicitly and thereby use whatever interface of my Domain Model classes I want to. (And using an interface for the Domain Model classes isn't necessary at all, of course.)

To use a custom IInterceptor implementation, you provide it as a parameter when instantiating ISession like this:

//A consumer _session = NHConfig.GetSessionFactory()     .OpenSession(new MyCustomInterceptorImpl());


Just watch out that you can't do everything in the validation code when using this approach; for example, you can't call out by using the same ISession instance, which might create a problem here and there, but we have touched on some strategies that can be used for dealing with this problem in Chapter 7, so I won't repeat those here.




Applying Domain-Driven Design and Patterns(c) With Examples in C# and  .NET
Applying Domain-Driven Design and Patterns: With Examples in C# and .NET
ISBN: 0321268202
EAN: 2147483647
Year: 2006
Pages: 179
Authors: Jimmy Nilsson

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net