views:

1408

answers:

5

I'm relatively new to NHibernate, but have been using it for the last few programs and I'm in love. I've come to a situation where I need to aggregate data from 4-5 databases into a single database. Specifically it is serial number data. Each database will have its own mapping file, but ultimately the entities all share the same basic structure (Serial class).

I understand NHibernate wants a mapping per class, and so my initial thought was to have a base Serial Class and then inherit from it for each different database and create a unique mapping file (the inherited class would have zero content). This should work great for grabbing all the data and populating the objects. What I would then like to do is save these inherited classes (not sure what the proper term is) to the base class table using the base class mapping.

The problem is I have no idea how to force NHIbernate to use a specific mapping file for an object. Casting the inherited class to the base class does nothing when using 'session.save()' (it complains of no mapping).

Is there a way to explicitly specify which mapping to use? Or is there just some OOP principal I am missing to more specifically cast an inherited class to base class? Or is this idea just a bad one.

All of the inheritance stuff I could find with regards to NHibernate (Chapter 8) doesn't seem to be totally applicable to this function, but I could be wrong (the table-per-concrete-class looks maybe useful, but I can't wrap my head around it totally with regards to how NHibernate figures out what to do).

+4  A: 

I don't know if this'll help, but I wouldn't be trying to do that, basically.

Essentially, I think you're possibly suffering from "golder hammer" syndrome: when you have a REALLY REALLY nice hammer (i.e. Hibernate (and I share your opinion on it; it's a MAGNIFICENT tool)), everything looks like a nail.

I'd generally try to simply have a "manual conversion" class, i.e. one which has constructors which take the hibernate classes for your individual Serial Classes and which simply copies the data over to its own specific format; then Hibernate can simply serialize it to the (single) database using its own mapping.

Effectively, the reason why I think this is a better solution is that what you're effectively trying to do is have asymmetric serialization in your class; i.e. read from one database in your derived class, write to another database in your base class. Nothing too horrible about that, really, except that it's fundamentally a unidirectional process; if you really want conversion from one database to the other, simply do the conversion, and be over with it.

McWafflestix
Yah, I agree, that makes sense. I was hoping for a silver bullet, but what you mentioned will perfectly work.
eyston
+1  A: 

This might help;

Using NHibernate with Multiple Databases

From the article;

Introduction

... described using NHibernate with ASP.NET; it offered guidelines for communicating with a single database. But it is sometimes necessary to communicate with multiple databases concurrently. For NHibernate to do this, a session factory needs to exist for each database that you will be communicating with. But, as is often the case with multiple databases, some of the databases are rarely used. So it may be a good idea to not create session factories until they're actually needed. This article picks up where the previous NHibernate with ASP.NET article left off and describes the implementation details of this simple-sounding approach. Although the previous article focused on ASP.NET, the below suggestion is supported in both ASP.NET and .NET.

...

The first thing to do when working with multiple databases is to configure proper communications. Create a separate config file for each database, put them all into a central config folder, and then reference them from the web/app.config.

...

nmiranda
A: 

I'm not 100% sure this will do what I need, but I found this googling today about NHibernate and anonymous types:

http://infozerk.com/averyblog/refactoring-using-object-constructors-in-hql-with-nhibernate/

The interesting part (to me, I'm new to this) is the 'new' keyword in the HQL select clause. So what I could do is select the SerialX from DatabaseX using mappingX, and pass it to a constructor for SerialY (the general/base Serial). So now I have SerialY generated from mappingX/databaseX, and (hopefully) I could then session.save and NHibernate will use mappingY/databaseY.

The reason I like this is simply not having two classes with the same data persisted (I think!). There is really no functional difference between this and returning a list of SerialX, iterating through it and generating SerialY and adding it to a new list (the first and best answer given).

This doesn't have the more general benefit of making useful cases for NHibernate mappings with inheritance, but I think it will do the limited stuff I want.

eyston
A: 

While it's true you will need a mapping file/class for each of those tables, there's nothing that stops you from making all of those classes implement a common interface.

You can then aggregate them all together into a single collection in your application layer (I.e. List) where each of those classes implement List)

You will probably have to write some plumbing to keep track of which session to store it under (since you're targetting multiple databases) if you wish to do updates. But the process for doing that will vary based on how you have things set up.

A: 

I wrote a really long post with code and everything to respond to Dan. It ended up I think I missed the obvious.

public class Serial
{
    public string SerialNumber {get; set;}
    public string ItemNumber {get; set;}
    public string OrderNumber {get; set;}
}

...

Serial serial = sessionX.get(typeof(Serial), someID);
sessionY.save(serial);

NHibernate should use mappingX for the get and mappingY for the save since the sessions aren't being shared, and the mapping is tied to the session. So I can have 2 mappings pointing to the same class because in any particular session there is only a single mapping to class relationship.

At least I think that is the case (can't test atm).

Unfortunately this specific case is really boring and not useful. In a different program of the same domain I derive from the base class for a specific portion of business logic. I didn't want to create a mapping file since it was just to make a small chunk of code easier. Anyways, I couldn't make it work in NHibernate due to the same reasons as my first question and did do the method McWafflestix describes to get around it (since it was minor).

That said I have found this via google:

http://jira.nhibernate.org/browse/NH-662

That is exactly the same situation, and it appears (possibly) addressed in NH 2.1+? I haven't followed up on it yet.

(note: Dan, in my case I am getting from several db's, only writing to one. I'm still interested in your suggestion about the interface because I think that is a good idea for other cases. Would you define the mapping against the interface? If I try and save a class that implements the interface that doesn't have a mapping definition, would NHibernate use the interface mapping? Or would I have to declare empty sublcasses in the mapping for each class that implements the interface mapping?)

eyston