简体   繁体   中英

Getting table-per-subclass objects in NHibernate

I've encountered a DB table called ScheduledJobs with a gazillion columns and a single matching C# object with an equal gazillion properties. I'm not thrilled with its design and wanted to break it up using a table-per-subclass strategy. Instead of

public class ScheduledJobs
{
    public int ID { get; set; } // always needed
    public int JobTypeID { get; set; } // always needed to distinguish A from B
    public int Foo { get; set; } // needed by Job A
    public int Bar { get; set; } // needed by Job B
}

I have

public abstract class ScheduledJob
{
    public int ID { get; set; }
    public ScheduledJobType JobType { get; set; }
}

public class ScheduledJobA : ScheduledJob
{
    public int Foo { get; set; }
}

public class ScheduledJobB : ScheduledJob
{
    public int Bar { get; set; }
}

I rewrote the NHibernate .hbm.xml file (no Fluent, sorry) to employ :

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
    <class name="ScheduledJob" table="ScheduledJobs" abstract="true" lazy="false">
        <id name="ID" column="ID" type="Int32" unsaved-value="0">
            <generator class="identity" />
        </id>
        <many-to-one name="ScheduledJobType" column="JobTypeID" class="ScheduledJobType" />

        <joined-subclass name="ScheduledJobA" table="ScheduledJobsA" lazy="false">
            <key column="JobID" />
            <property name="Foo" type="Int32" />
        </joined-subclass>

        <joined-subclass name="ScheduledJobB" table="ScheduledJobsB" lazy="false">
            <key column="JobID" />
            <property name="Bar" type="Int32" />
        </joined-subclass>
    </class>
</hibernate-mapping>

Great! My trouble is, I can't figure out how to wisely fetch subclassed jobs. The benefit of one big table was not having to worry about types or casting:

ScheduledJob job = Repository.ScheduledJob.Get(id);

In my setup, I have the same ID (which should be enough; it's still unique), but the type is unknown to me: I have to fetch the abstract job, examine JobTypeID, find the associated C# subclass, and refetch it under that subclass.

I have the ability to bring in the JobTypeID if I need it. I still have to pair up that ID with the job subclass table that's associated with it.

In short, I need to be able to have the ScheduledJob object I receive from NHibernate be the correct subclass with as little intervention from me as possible. The ability to use discriminators here would be great, but official docs say does not permit it. This design makes me feel like I'm fundamentally misunderstanding something; feel free to point me in the right direction.

Thanks!

In my setup, I have the same ID (which should be enough; it's still unique), but the type is unknown to me: I have to fetch the abstract job, examine JobTypeID, find the associated C# subclass, and refetch it under that subclass.

Actually, you neither have to examine JobTypeID , nor fetch it again. That's NHibernate's job: on the initial fetch it will determine the appropriate derived type and automatically instantiate an object of this type for you.

If you need to query for the type after an object has been fetched, you can use C# type-checking and casting:

ScheduledJob job = Repository.ScheduledJob.Get(id);
if (job is ScheduledJobA)
{
      ScheduledJobA jobA = (ScheduledJobA)jobA;
      ProcessJobA(jobA);
}
else if (job is ScheduledJobB)
{
      ScheduledJobB jobB = (ScheduledJobB)jobB;
      ProcessJobB(jobB);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM