1
votes

I am sure someone has to have done this before - looking at the previous queries it possibly cannot be done with Fluent - but here goes:

I have the following mappings

As you can probably spot - this is not going to work because the keys on the child table do not match the parent table and so the error will be that the number of fields on the foreign key contract don't match. However, I cannot change the underlying tables (and the relationship is a valid one). Is there a way around this in fluent nhibernate so I can somehow ignore the expected join on both composite fields and only join on the one which matches (i.e field_one?) Hibernate expects that field one and field two are present on both mappings.

public ParentMap()
{
    Table("dbo.SOMEPARENT");
    OptimisticLock.None();
    LazyLoad();
    CompositeId()
    .KeyReference(x => x.FieldOne, x => x.Access.CamelCaseField(Prefix.Underscore), "field_one")
    .KeyReference(x => x.FieldTwo, x => x.Access.CamelCaseField(Prefix.Underscore), "field_two");

    HasMany(x => x.ChildData)
            .Access.CamelCaseField(Prefix.Underscore)
            .Cascade.AllDeleteOrphan()
            .KeyColumns.Add("field_one")
            .NotFound.Ignore();

}

public ChildDataMap()
{
Table("dbo.SOMECHILD");
OptimisticLock.None();
LazyLoad();

CompositeId()
    .KeyProperty(x => x.FieldOne, x => x.Access.CamelCaseField(Prefix.Underscore).ColumnName("field_one"))
    .KeyProperty(x => x.FieldTwo, x => x.Access.CamelCaseField(Prefix.Underscore).ColumnName("field_two"))
    .KeyProperty(x => x.FieldThree, x => x.Access.CamelCaseField(Prefix.Underscore).ColumnName("field_three"))
    .KeyProperty(x => x.FieldFour, x => x.Access.CamelCaseField(Prefix.Underscore).ColumnName("field_four"));
Map(x=>x.DontExecTrigger).Column("dont_exec_trigger").Access.CamelCaseField(Prefix.Underscore);
Map(x=>x.DateField).Column("date_field").Access.CamelCaseField(Prefix.Underscore);
Map(x=>x.DataField).Column("data_field").Access.CamelCaseField(Prefix.Underscore);

References(x => x.Parent)
    .Access.CamelCaseField(Prefix.Underscore)
    .Cascade.All()
    .Fetch.Select()
    .Columns("field_one")
    .NotFound.Ignore()
    .Not.LazyLoad();

}

1

1 Answers

1
votes

From a purely database point of view, if a ChildDataMap FieldOne value always appears in ParentMap FieldOne and FieldOne is unique in ParentMap then there is a foreign key from the former to the latter. But also it means FieldOne is a candidate key of (unique in) ParentMap.

You should declare the FK and UNIQUE database constraints. You say you can't change the table but if the constraint is valid then it is not going to affect any useres of it. That ought to allow you to declare that ChildDataMap FirstOne References ParentMap FirstOne. The two-column set can still be declared PK (assuming it is). But if ParentMap FieldTwo is also unique, it should be declared UNIQUE also and so become available as one-column FK target.

Maybe the UNIQUE constraint and/or FK are already declared. Maybe you should just be declaring the corresponding unique property for FirstOne in ParentMap. The KeyColumns.Add ought rely on its being there and allow you to declare the References in ChildDataMap. But I guess that's where your code is not valid.

If Hibernate doesn't automatically join on same-named fields then you could just not declare the References and do your own join on the one field to get a set of references of which of course there will be only one element.

It's not clear what you mean by "you can't change the tables" (does that include, you can't have valid constraints added?) or "the relationship is a valid one" (does that mean, FieldOne in Parent is unique?). It would also help if you posted all the relevant code: namely the table delarations including constraints.

If you can have a new table defined, you can add StricterParentMap with the added constraints and have ParentMap declared as a view of it. This wouldn't affect others' use of it and might not count as "can't change".