How to map a joined-subclass with a composite key with non-matching column names - nhibernate

I have two tables, say:
PAYMENT
------------------------------
OrderId INT PK
PaymentId INT PK
Amount FLOAT
ChildPaymentRowNum INT
CARD_PAYMENT
------------------------------
OrderId INT PK
PaymentRowNum INT PK
CardType STRING
CHEQUE_PAYMENT
------------------------------
OrderId INT PK
PaymentRowNum INT PK
CheckNumber INT
No, I didn't make this DB and no I can't change it. I want to map CARD_PAYMENT and CHEQUE_PAYMENT as joined-subclasses of PAYMENT. The difference in this model from the examples I've found is that I'm both using a composite key and one of the column names in the foreign table doesn't match.
I think if it were not a composite key I could do this:
<joined-subclass name="CardPayment" table="CARD_PAYMENT" extends="Payment">
<key column="PaymentRowNum" foreign-key="ChildPaymentRowNum">
</joined-subclass>
And if the names matched on the composite key I could do this:
<joined-subclass name="CardPayment" table="CARD_PAYMENT" extends="Payment">
<key>
<column="OrderId">
<column="PaymentRowNum">
</key>
</joined-subclass>
But, while I'd like to do something like this I'm pretty sure it's illegal:
<!-- NO GOOD -->
<joined-subclass name="CardPayment" table="CARD_PAYMENT" extends="Payment">
<key>
<column="OrderId" foreign-key="OrderId">
<column="PaymentRowNum" foreign-key="ChildPaymentRowNum">
</key>
</joined-subclass>
So, how would I do something like this?
BONUS POINTS: if you can tell me how to do it with NHibernate.Mapping.Attributes, but if not I can probably figure it out.

The foreign-key attribute is used to specify the name of a foreign key constraint (not column!) that should be created by the NHibernate schema generation tool. It has no affect on NHibernate during runtime.
Why do you want to specify the key column name of the base class in the subclass key? Even the NHibernate documentation for joined-subclass uses different column names in both tables: http://nhibernate.info/doc/nh/en/index.html#mapping-declaration-joinedsubclass

Related

defining Unique Key in hibernate and how?

<many-to-one name="attachment" class="AttachmentEntity" lazy="false"
fetch="select" cascade="delete">
<column name="SPA_ATTACHMENT_ID" not-null="true" unique-key="IDX_AMT_COND_01"/>
</many-to-one>
What is the Unique Key doing and how will it work as a string?
As per the JBoss documentation,
A unique-key attribute can be used to group columns in a single,
unique key constraint. The attribute overrides the name of any
generated unique key constraint.
Typical use case for unique-key would be, when you want the values of multiple columns as a whole to be unique.
For example:
class Department {...}
class Employee {
Integer employeeId;
Department department;
}
So, to ensure that 2 Employee objects with same employeeId and department are not persisted, we can use the unique-key attribute with same value EmpIdDept on the 2 columns EMP_ID and DEPT_ID to enforce the uniqueness constraint on them as a whole:
<property name="employeeId" column="EMP_ID" unique-key="EmpIdDept"/>
<many-to-one name="department" column="DEPT_ID" class="Department" unique-key="EmpIdDept"/>
The string specified as the attribute value, i.e. IDX_AMT_COND_01 in your case, is just the name of the multi column unique constraint.
Also check this answer and this one (to achieve the same using #UniqueConstraint)
NOTE: to use single column unique constraint, you need to use
unique="true"

ColdFusion: ORM Relationship with LinkTable and Multiple Foreign Keys

My database structure mainly consists of multiple primary keys per table, therefore multiple columns are required per join. I'm trying to use ColdFusion (11 to be specific) ORM relation property that has a linktable. I think the issue is with two keys on one side of the many-to-many relationship and just one on the other. Here is what I've tried without success:
Table Setup
Staff StaffSites Sites
============ ============ ===========
YearID (PK) --- YearID (PK)
StaffID (PK) --- StaffID (PK) SiteName
StaffName SiteID (PK) --- SiteID (PK)
Staff ORM CFC
component persistent=true table='Staff' {
property name='id' column='StaffID' fieldType='id';
property name='year' column='YearID' fieldType='id';
property name='name' column='StaffName';
property name='sites'
cfc='site'
linkTable='StaffSites'
fkColumn='YearID,StaffID'
inverseJoinColumn='SiteID'
mappedBy='id'
fieldType='many-to-many'
lazy=true;
}
Site ORM CFC
component persistent=true table='Sites' {
property name='id' column='SiteID' fieldType='id';
property name='name' column='SiteName';
}
ColdFusion Error
collection foreign key mapping has wrong number of columns: staff.sites type: integer
If the join table has multiple foreign key columns (that reference the
composite key of the target table), then you must use comma-separated
column names.Also, the order in which the column names are specified
must match the order of composite keys defined.
http://help.adobe.com/en_US/ColdFusion/9.0/Developing/WS5FFD2854-7F18-43ea-B383-161E007CE0D1.html
Composite key should be supported.
Try switching the id's since you define staff id first, and also specify the orm type on the id's just in case. Also, try swapping inverseJoinColumn with fkColumn, I never remember which should be which but that'd be something I'd try.

How force ID generator for class "indentity" to increment for last inserted Id in SQL

I want ask for some advice about,why my <generator class="identity" /> generate id in table not as as last inserted + 1 but like e.g last insert ID is 5, and when save record then a new Id has be for example 7, so ID value 6 is skipped
(i need use identity not increment class due to advantage of this "identity" class for my mySql database)
because in my case i need same ID value for primary key and foreign key, must be equals,,but in this case i got Primary key 7 and Foreign key will generate also but not as incremented by last ID,
both class has Hibernate mappings, with this <generator class="identity" />
What i must use so that to obtain both incremented ID with new record by "identity"?
You have to create your table with a primary key using "AUTO_INCREMENT" such as :
CREATE TABLE person (
id BIGINT NOT NULL AUTO_INCREMENT,
name CHAR(30) NOT NULL,
PRIMARY KEY (id)
)
Then your GenerationType.IDENTITY must do the job.

Nhibernate mapping join on foreign key

Is there any way to get Nhibernate mapping to perform a join between a child and parent tables
I have a product table and a product group table. there is a key between these tables of GroupId. When i use a join in mapping for a Product it tries to Join on the ProductId to the GroupId instead of the GroupId to GroupId.
Is there no easy way to do this?
Your mappings are probably wrong.
If Product has a reference (FK) to Group, it should be mapped as:
<many-to-one name="Group" column="GroupId"/>
If that's not the case, please post your classes.
Is the foreign key set up in your database? If not add it in the database and try including it in the reference in your Nhibernate Product mapping:
e.g.,
<many-to-one name="Group" column="GroupId" foreign-key="FK_Product_ProductGroup" />
Note: foreign-key value there is just a guess of what it would be called, grab it from the database properties :)

How can an indexed many-to-many set be mapped in NHibernate?

Consider an entity, Entry, that contains a collection of another entity (many-to-many), Category, such that the Entry can be associated with a given Category no more than once (implying a "set" and constrained by the database) and the ordering of the Category entities within the collection is fixed and is defined by an extra field on the mapping table (implying a "list"). What would be the proper mapping for such a case?
Additional details/specifics about the problem this question is trying to address:
Since a <set> doesn't use an <index>, and we can easily maintain uniqueness of the Category entities in the application layer (as opposed to using NHibernate for this), using <list> seems to make sense since it will automatically handle the update of the ordering value in the extra field on the mapping table (which is the biggest "feature" I'd like to use). Unfortunately, when updating the collection, we encounter constraint violations due to the manner in which NHibernate performs the updates (even when the new collection values wouldn't ultimately cause a constraint violation) since we have a unique constraint on the database between the related objects in the mapping table.
More specifically, consider the following database schema:
CREATE TABLE Category (
id int IDENTITY PRIMARY KEY,
name varchar(50)
)
CREATE TABLE Entry (
id int IDENTITY PRIMARY KEY,
data varchar(50)
)
CREATE TABLE EntryCategory (
categoryId int REFERENCES Category (id),
entryId int REFERENCES Entry (id),
index int,
PRIMARY KEY (categoryid, entryId)
)
And the following mappings:
<class name="Category">
<id name="Id">
<generator class="native">
</id>
<property name="name"/>
</class>
<class name="Entry">
<id name="Id">
<generator class="native">
</id>
<property name="data"/>
<list name="Categories" table="EntryCategory">
<key column="entryID"/>
<index column="index"/>
<many-to-many class="Category" column="categoryID"/>
</list>
</class>
Let's consider the initial database state containing the following data:
EntryId CategoryID Index
555 12 0
555 13 1
555 11 2
555 2 3
On load of Entry #555, its Categories list will contain the following elements:
Index Category ID
0 12
1 13
2 11
3 2
If we update this list to remove an element (category 13 at index 1) to look like the following:
Index CategoryID
0 12
1 11
2 2
NHibernate will first delete the entry with highest index value (since the size has reduced), executing the following:
DELETE FROM EntryCategory WHERE entryId = #p0 AND index = #p1;
#p0 = '555', #p1 = '3'
After this update the data in the database looks like this:
EntryId CategoryID Index
555 12 0
555 13 1
555 11 2
Next, it attempts to update the values with the right mappings and starts with this updaet statement:
UPDATE EntryCategory SET CategoryID = #p0 WHERE EntryId = #p1 AND Index = #p2;
#p0 = '11', #p1 = '555', #p2 = '1'
This fails with Violation of PRIMARY KEY constraint since it's attempting to make the data look like this:
EntryId CategoryID Index
555 12 0
555 11 1
555 11 2
It seems that what really needs to happen is that the EntryId and CategoryId are left alone and the Index values are updated instead of leaving the EntryId and Index values alone and updating the CategoryId values. But even in that case, there could be issue if, say, there were also a UNIQUE constraint on EntryID and Index (in addition to the primary key on EntryID and CategoryID).
I think that you'll have to loosen up your constraints to get this to work. Like you said, even if NHibernate updated the index instead of the categoryId, "there could be issue if, say, there were also a UNIQUE constraint on EntryID and Index". This is what I would suggest:
-- Looser constraints. This should work.
CREATE TABLE EntryCategory (
id int IDENTITY PRIMARY KEY,
categoryId int REFERENCES Category (id),
entryId int REFERENCES Entry (id),
index int
);
CREATE INDEX IX_EntryCategory_category ON EntryCategory (entryId, categoryId);
CREATE INDEX IX_EntryCategory_index ON EntryCategory (entryId, index);
I mean, ideally you would have something like the following - but it would be nearly impossible to run any UPDATE queries on it:
-- Nice tight constraints - but they are TOO tight.
CREATE TABLE EntryCategory (
categoryId int REFERENCES Category (id),
entryId int REFERENCES Entry (id),
index int,
PRIMARY KEY (entryId, categoryId),
UNIQUE KEY (entryId, index)
);
Whenever I'm stuck in a situation like this where what I really want is a unique key but for some reason I'm forced to do without it, I settle for an index instead.
In case it's helpful, Ayende has an example with a very similar mapping - a many-to-many list. He doesn't talk about the database schema, though.
Have a look at Oren Eini's blog about the <map> and <set> tags particularly the <map> blog. I think that is what you are after.
<map>
<set>