Consider the mapping file below. Both classes have a different notion of what the businessId is, which the object model handles, but it is acceptable to store it as a plain string in one column. I also want them each to have the same relationship with the Allocations set, which is the main reason I want them mapped using inheritance.
While the odds of a business id for a Project being the same as an Account are remote today, it would be ideal if there were a way to make the combination of the businessId and discriminator both part of the natural-id. This is not allowed, maybe for some good reason that I am not seeing.
Can I improve this mapping in some obvious way?
Cheers,
Berryl
<class name="ActivitySubject" table="ActivitySubjects" discriminator-value="BASE_CLASS">
<id name="Id" unsaved-value="0">
<column name="ActivitySubjectId" />
<generator class="hilo" />
</id>
<discriminator column="ActivitySubjectType" type="System.String" />
<natural-id mutable="true">
<property name="BusinessId" length="25" not-null="true" />
</natural-id>
<property name="Description" length="75" not-null="true" />
<set access="field.camelcase-underscore" cascade="all-delete-orphan" inverse="true" name="Allocations">
<key foreign-key="Allocations_Resource_FK">
<column name="ActivityId" />
</key>
<one-to-many class="Allocation />
</set>
<subclass name="Account" discriminator-value="ACCOUNT" />
<subclass name="SProject" discriminator-value="PROJECT" />
Here is the way I finally got both columns to be part of the same unique index:
<discriminator type="System.String" >
<column name="ActivitySubjectType" unique-key="ActivitySubjectTypeBusinessId" />
</discriminator>
<property name="BusinessId" length="25" not-null="true" node="1" unique-key="ActivitySubjectTypeBusinessId"/>
Don't use natural ids for primary keys. I would use a synthetic key, a database generated identity or a GUID for the primary key and add a unique constraint on the combination of BusinessId and ActivitySubjectType.
Related
I'm having problems getting the right hbm.xml for mapping a Many-to-One relationship over a link table:
<class name="Car" table="Cars" lazy="true">
<id name="CarKey" type="int">
<generator class="native" />
</id>
[properties]...
<many-to-one ??? />
</class>
<class name="Driver" table="Drivers" lazy="true">
<id name="DriverKey" type="int">
<generator class="native" />
</id>
[properties]...
</class>
<class name="CarDriverLink" table="CarDriverLinks" lazy="true">
<id name="CarDriverLinkKey" type="int">
<generator class="native" />
</id>
<property name="CarKey">
<column name="CarKey" sql-type="int" not-null="true" />
</property>
<property name="DriverKey">
<column name="DriverKey" sql-type="int" not-null="true" />
</property>
</class>
Imagining that in this example a car can have only one driver, but a driver can have multiple cars, how would I add a many-to-one relationship onto the Car mapping to allow a Car to see which Driver can drive it, using the CarDriverLinks table?
So for a one-to-many, many-to-one you don't necessarily need a cross reference table in between. That will give you a many-to-many relationship. Since each car will have only one driver, you can add a DriverID to your Car table and class. Your driver can still have multiple cars. I use Fluent NHibernate, so I don't really remember the XML mapping but check out this question that explains the rest of what you're looking for. One To Many, Many To One - NHibernate
I've got a class which contains a list of associated objects.
I've map it as follows:
<class name="MyDto" table="`MyView`" mutable="false" lazy="false">
<id name="Id" column="ID" type="int">
<generator class="assigned" />
</id>
<set name="Days" cascade="all-delete-orphan" lazy="false" >
<key column="Id" />
<one-to-many class="MyAssociatedObj"/>
</set>
</class>
<class name="MyAssociatedObj" table="V_SC_NEED" mutable="false" lazy="false" >
<id name="Id" column="`ID2`" type="int">
<generator class="assigned" />
</id>
<property type="DateTime" not-null="true" name="DayDate" column="`Date`" />
<component name="Audit">
<property type="string" not-null="true" length="255" name="Username" column="`USERNAME`" />
<property type="decimal" not-null="true" name="PreviousValue" column="`PrevVal`" />
</component>
</class>
What I wanted to do is to get a list of MyDto Object, filtering by my associated object, MyAssociatedObject.
Which means, for example, if i do:
UnitOfWork.Session.CreateCriteria<MyDto>().List<MyDto>()
I get a list of 42 lines.
Now, I want to filter them by my associated object, by a restriction of between.
the problem is that when i do so:
UnitOfWork.Session.CreateCriteria<MyDto>().CreateAlias("Days", "days").Add(Restrictions.Between("days.DayDate", query.FromDate, query.ToDate));
I'm getting, somehow 684 rows ! (some cartesial product or something).
Any advise?
Many thanks !
You are getting more rows in the second query because you are JOINing with MyAssociatedObj, which seems to be in a many-to-one relationship with your MyDTO class.
If you want to filter out duplicates of MyDTO, you can use the DistinctRootResultTransformer:
UnitOfWork.Session.CreateCriteria<MyDto>().CreateAlias("Days", "days")
.Add(Restrictions.Between("days.DayDate", query.FromDate, query.ToDate))
.SetResultTransformer(
new NHibernate.Transform.DistinctRootEntityResultTransformer());
Hope it helps.
I am working with an Oracle legacy database and I am trying to map a relationship with two tables. Unfortunately the company who designed the database used composite keys.
I've got this table (ORDERS) which has a primary key composed on 3 fields: ordernumber (number), version and company.
<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="BpSalesOrders.Domain"
namespace="BpSalesOrders.Domain">
<class name="Order" table="OCSAORH" mutable="false" where="OCHAMND = 0">
<cache usage="read-only"/>
<composite-id>
<key-property name="Number" column="OCHORDN" type="String" length="10"></key-property>
<key-property name="Ver" column="OCHAMND" type="Int32"></key-property>
<key-property name="Company" column="OCHCOSC" type="String" length="5"></key-property>
</composite-id>
<property name="Reference" column="OCHOCNO" type="String" length="25"></property>
<property name="Date" column="OCHOCDT" type="Int32"></property>
<property name="Status" column="OCHSTA1" type="Char"></property>
<property name="LineOfCreditStatus" column="OCHSTA4" type="Char"></property>
<property name="WareHouse" column="OCHRESP" type="String"></property>
<set name="OrderLines" access="field.pascalcase-underscore" inverse="true" lazy="true" mutable="false">
<key>
<column name="OCLORDN" not-null="true"/>
<column name="OCLAMND" not-null="true" default="0"/>
<column name="OCLCOSC" not-null="true"/>
</key>
<one-to-many class="OrderLine" not-found ="ignore"/>
</set>
<set name="OrderReleases" access="field.pascalcase-underscore" inverse="true" lazy="true" mutable="false">
<key>
<column name="ORLORDINE" not-null="true" />
<column name="ORLSOCIETA" not-null="true"/>
</key>
<one-to-many class="OrderRelease" not-found ="ignore"/>
</set>
</class>
</hibernate-mapping>
There's a relation with OrderLines which works fine cause that table has the same exact key structure.
I am having problem with the OrderReleases relation. That table has got a primary key composed on a OrderNumber, Company and date. There's no version here:
<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="BpSalesOrders.Domain"
namespace="BpSalesOrders.Domain">
<class name="OrderRelease" table="OCBPORDRIL" mutable="true">
<composite-id>
<key-property name="Company" column="ORLSOCIETA" type ="String" length="5"></key-property>
<key-property name="OrderNumber" column="ORLORDINE" type ="String" length="10"></key-property>
<key-property name="RequestDate" column="ORLDATARICHIESTA" type ="Int32"></key-property>
</composite-id>
<property name="Status" column="ORLSTATUS" type="Char" length="1"></property>
<property name="StatusMessage" column="ORLSEGNALAZIONE" type="String" length="90"></property>
<property name="ProcessingDate" column="ORLDATAELABORA" type ="Int32"></property>
</class>
</hibernate-mapping>
Considering that the relationship is one-to-many I would like to join the table Orders and OrderRelease on OrderNumber and Company. If I try to do that (as in the example) nHibernate throws an exception telling me that the key it's trying to map is composed with 3 fields.
Is there a way to create an non-existing column which wouldn't be persisted so that I can setup my mapping and relations?
Any help will be apreciated.
Ended up creating a view with a fake column.
I have a couple of tables that I want to map to classes. The tables look like this:
Asset
---------
AssetId
AssetName
Product
---------
ProductId
ProductName
AssetId
Disposal
---------
DisposalId
AssetId
DisposalDate
Basically what I want to do is join the Product Table to the Disposal table on AssetId so that my Product has a collection of Disposals joined by asset. I have defined the following mapping but NHibernate (1.2) seems to ignore the key column defined in the bag and chooses to join the Product table to the Disposal table by ProductId (ie Product.ProductId = Disposal.AssetId). I'm not sure if this is a bug or if I'm not defining it properly but if anyone has a way to do this I'd be most greatful.
<class name="Product" table="Product" lazy="false">
<id name="ProductId" column="ProductId" type="int">
<generator class="native" />
</id>
<property name="ProductName" column="ProductName"/>
<bag name="Disposals" fetch="join" >
<key column="AssetId" foreign-key="AssetId/>
<many-to-many class="Disposal"/>
</bag>
</class>
Have you got your Disposals mapped to Products?
Your schema doesn't unique relate a Disposal to a Product. A Disposal can only relate to an Asset, not a Product.
You schema says to me that an Asset has many Products, and an Asset has many Disposals. There's nothing that says a Disposal is for a particular product.
The clean way:
<class name="Product" table="Product" lazy="false">
<id name="ProductId" column="ProductId" type="int">
<generator class="native" />
</id>
<property name="ProductName" column="ProductName"/>
<many-to-one name name="Asset" class="Asset" column="AssetId" />
</class>
<class name="Asset">
<id name="AssetId" >
<generator class="native" />
</id>
<property name="AssetName" />
<bag name="Disposals">
<key column="AssetId" />
<many-to-many class="Disposal" />
</bag>
</class>
foreign-key is used for DDL, I think it is the name of the foreign key constraint generated by schema export.
You can try property-ref, not completely sure if it works:
<class name="Product" table="Product" lazy="false">
<id name="ProductId" column="ProductId" type="int">
<generator class="native" />
</id>
<property name="ProductName" column="ProductName"/>
<property name="AssetId" />
<bag name="Disposals" fetch="join" >
<key column="AssetId" property-ref="AssetId/>
<one-to-many class="Disposal"/>
</bag>
</class>
I need to create a new Many-To-One relationship on my User entity which joins against another entity. The problem is the other entity has a compound key of which 1 field is a field in the User entity and the other is a field in another Many-To-One entity.
User.Key -> User.NewThing.Key
User.SubThing.Key -> User.NewThing.Key
Below is the invalid mapping file I am ideally wanting to use where JeanieUserTyped is my newthing and the ApplicationId is the key in question which comes from ShortCode.ApplicationId.
Question is how do I tell it to map the application part of the compound key?
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="JeanieMaster.Domain.Entities" assembly="JeanieMaster.Domain">
<class name="JeanieUser" table="DBSVR1.Jeanie_Master.dbo.JeanieUser" select-before-update="false" optimistic-lock="none">
<id name="Id" column="UserId" type="Int32">
<generator class="identity"/>
</id>
<property name="Mobile" type="String"/>
<property name="UniqueReoccurBillingRefId" type="String"/>
<property name="DateJoined" type="DateTime"/>
<property name="IsActive" type="Boolean"/>
<many-to-one name="MobileNetwork" class="MobileNetwork" column="MobileNetworkId" />
<many-to-one name="ShortCode" class="ShortCode" column="ShortCodeId" />
<many-to-one name="MobileHandset" class="MobileHandset" column="HandsetId" />
<many-to-one name="JeanieUserTyped" class="JeanieUserTyped">
<column name="Mobile" />
<column name="ApplicationId" />
</many-to-one>
</class>
</hibernate-mapping>
Can you give more details, sounds like you have 3 entities,
User
SubThing
NewThing
Where NewThing resolves a Many-to-Many with User and SubThing - am I close?
Maybe like this:
User -< SubThing
| |
/\ /\
NewThing
I don't suppose the composite key stuff in nhibernate is relevant?