Search code examples
c#nhibernatefluent-nhibernatefluent-nhibernate-mapping

Two tables with the same structure and schema but different names requiring inserts and updates to one table - NHibernate


I have two different tables with the same structure and schema in one database.

Comp.Employee
Comp.EmployeeTemp

Entity class:

public class Employee 
{
   public virtual string Name {get;set;}
}

NHibernate fluent mapping:

public class EmployeeMap : ClassMap<Employee> 
{
   public EmployeeMap()
   {
      Map(x => Name);
   }
} 

public class EmployeeTempMap : ClassMap<Employee> 
{
   public EmployeeTempMap()
   {
      Map(x => Name);
   }
} 

var manager = new Employee { Name = "Tom"}
Session().SaveOrUpdate("EmployeeTemp", manager)

I want to save the manager entity to Comp.EmpoyeeTemp table and not to Comp.Employee. I need to be able write to both tables but not at the same time using the same Employee entity. How can I do this in NHibernate and fluent mapping?

Update: Updated my question to include the EmployeeTempMap mapping and the overloaded call to SaveOrUpdate()


Solution

  • There is a rarely known/used NHibernate feature called "entity-name", which might enable you to do what you are trying to do - at least to some degree.


    Background information:

    An introduction to the feature can be found here: Mapping the same class to a view and a table using entity-name (also applies to two tables with the same structure).

    Fluent NHibernate also supports this feature, as can be seen in the source: fluent-nhibernate ClassMap

    Relevant code from the above link:

    /// <summary>
    /// Specifies an entity-name.
    /// </summary>
    /// <remarks>See http://nhforge.org/blogs/nhibernate/archive/2008/10/21/entity-name-in-action-a-strongly-typed-entity.aspx</remarks>
    public void EntityName(string entityName)
    {
        attributes.Set("EntityName", Layer.UserSupplied, entityName);
    }
    

    Disclaimer: (the following code is untested but should put you on the right track. Feel free to edit when something is wrong or missing)

    As mentioned in my comment to your question above, you can use inheritance for the class mappings like this (shortened example):

    // Base class
    public class BaseEmployeeMap<T> : ClassMap<T> where T : Employee
    {
        public BaseEmployeeMap()
        {
            Map(p => p.Name);
            // add all Properties that are common to both Employee and EmployeeTemp
        }
    } 
    
    // Mapping for Employee
    public class EmployeeMap : BaseEmployeeMap<Employee>
    {
        public EmployeeMap() : base()
        {
            EntityName("Employee");
        }
    } 
    
    // Mapping for EmployeeTemp
    public class EmployeeTempMap : BaseEmployeeMap<Employee>
    {
        public EmployeeTempMap() : base()
        {
            EntityName("EmployeeTemp");
        }
    } 
    

    Now you can query and insert items by using the overloaded methods and supplying the EntityName:

    // both tempEmployee and employee will be instances of class "Employee"
    var tempEmployee = session.Get("EmployeeTemp", id);
    var employee = session.Get("Employee", id);
    
    session.SaveOrUpdate("EmployeeTemp", tempEmployee);
    session.SaveOrUpdate("Employee", employee);
    

    However, I have not verified that your goal (not having to "convert" an Employee to EmployeeTemp) can be achieved with this, because NHibernate might throw an error when loading the object with EntityName EmployeeTemp and trying to save it with the EntityName Employee. You might need to manually Evict() it from the session and then Save() it with the desired EntityName. (You might also need to clear the ID of the object.)

    Suggestion to make things simpler:

    I don't know the background of the design for two different tables with the same structure, but if your database structure is not set in stone, you could simply use one table employee and add a column temp and use that as a filter for your queries. When changing an EmployeeTemp to an Employee you would only have to flip the switch from temp = 1 to temp = 0.

    For a similar case look here on SO: Multiple DB tables for one property in model