I have two tables that have no direct relationships between them.
There is then a third table, a link table, which simply references the
two tables with foreign keys. A record in this third table is meant
to be unique (although it isn't enforced with a key yet!) and it
indicates that a row in Table1 is related to only 1 row in Table2 and
vice-versa.
Questions:
What classes should I have?
It seems like I ought to have just two classes that each have a single
reference to each other.
How do I go about mapping this?
I can't use HasOne because that requires that the keys in each table
are unique, and besides I have the link table in the way.
I could create 3 classes, one for each table, but I can't seem to
avoid implementing one-to-many relationships (which I couldn't get to
work either).
I intend to add a composite key to the link table to enforce the
unique relationship, in case that assists with the mapping?
Simplified schema, if it helps:
Table1 (Table1_Id (pk), Name)
Table2 (Table2_Id (pk), Name)
Table3 (Table1_Id (fk), Table2_Id (fk))
Thanks in advance
Boz
--
You received this message because you are subscribed to the Google Groups "Fluent NHibernate" group.
To post to this group, send email to fluent-n...@googlegroups.com.
To unsubscribe from this group, send email to fluent-nhibern...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/fluent-nhibernate?hl=en.
I just found someone doing a similar thing:
http://stackoverflow.com/questions/497548/nhibernate-2-0-mapping-a-composite-id-and-many-to-one-relationship-causes-in
which says you need 3 classes, with the link table class referencing
the other two tables, and it seems a composite key mapping does the
job. Below is what I've got so far. Note that Table1 and Table2 are
identical for this simplified example, and their maps are
straightforward and not shown below.
public class Table1 // Table2 identical
{
public virtual decimal Id {get;set;}
public virtual string Name {get;set;}
}
public class Table3
{
public virtual Table1 Table1 {get;set;}
public virtual Table2 Table2 {get;set;}
}
public class Table3Map: ClassMap<Table3>
{
Table("Table3");
CompositeId()
.KeyProperty(x => x.Table1, "Table1_Id")
.KeyProperty(x => x.Table2, "Table2_Id")
Reference(x => x.Table1, "Table1_Id")
Reference(x => x.Table2, "Table2_Id")
}
So, comments on the above approach would be appreciated.
But also, I get the following error when running this:
"Could not determine type for: MyNamespace.Table1"
On Jan 25, 5:17 pm, Hudson Akridge <hudson.akri...@gmail.com> wrote:
> The only way I can think of mapping that would be using a ManyToMany between
> the two of them (even though you're only ever going to get a single row
> back), and then projecting that backing field with a public property that
> just does something like a return backingCollectionField.First();
>
> I don't know if there's a better way to do it. May jump onto:http://groups.google.com/group/nhusersand ask them (using NH xml mappings
> > fluent-nhibern...@googlegroups.com<fluent-nhibernate%2Bunsu...@googlegroups.com>
To unsubscribe from this group, send email to fluent-nhibern...@googlegroups.com.
My preference is not to have 3 classes, it just doesn't feel right,
and it means I can't easily navigate from a Table1 to it's Table2
without hanging on to Table3 references somewhere. So if it's
possible to use two ManyToMany for this, that certainly sounds the
right approach.
Could you help me a bit further with this implementation? I assume
you're talking about having non-virtual properties that hide the
implementation like this (get/set implementation elided):
public class Table1
{
public virtual decimal Id {get;set;}
public virtual string Name {get;set;}
public Table2 Table2 {get {...} set {...}
}
public class Table2
{
public virtual decimal Id {get;set;}
public virtual string Name {get;set;}
public Table1 Table1 {get {...} set {...}
}
But do you then have protected virtual properties for Table1 and
Table2 aswell so that they can be mapped with Fluent mappings? I find
this aspect hard to visualise, both in terms of the entities and the
mappings. Sorry to be slow, but if you could help me further here it
would be much appreciated.
Boz
> >http://stackoverflow.com/questions/497548/nhibernate-2-0-mapping-a-co...
> >http://groups.google.com/group/nhusersandask them (using NH xml mappings
> > <fluent-nhibernate%2Bunsu...@googlegroups.com<fluent-nhibernate%252Buns...@googlegroups.com>
So, taking my classes from previous post, below is a modified Table1
and Table3
public class Table1 // Table2 similar to Table1
{
public virtual decimal Id {get;set;}
public virtual string Name {get;set;}
public virtual Table2
{
get
{
result listOfTable3[0].Table2; // obviously with collection
validation!
}
}
protected virtual IList<Table3> listOfTable3 {get; set;} // hidden
away
public Table1()
{
listOfTable3 = new List<Table3>();
}
}
public class Table3 // the link class
{
public virtual Table1 Table1 {get;set;}
public virtual Table2 Table2 {get;set;}
public override bool Equals(object obj) {/* return combined equality
check */}
public override int GetHashCode() {/* return combined hashcode */}
}
You need the Equals and GetHashCode for the .KeyReference() maps
below.
And so the mappings required to get Table1 to reference Table2 via the
link class Table3:
public class Table3Map : ClassMap<Table3> // As per Hudson's reply
{
public Table3Map()
{
Table("Table3");
CompositeId()
.KeyReference(x => x.Table1, "Table1_Id")
.KeyReference(x => x.Table2, "Table2_Id")
}
}
public class Table1Map : ClassMap<Table1> // Table2Map similar
{
public Table1Map()
{
Table("Table1");
Id(x => x.Id, "Table1_Id");
Map(x => x.Name, "Name");
HasMany<Table3>(Reveal.Property<Table1>("listOfTable3"))
.Table("Table3")
.KeyColumn("Table1_Id")
.Inverse();
}
}
The use of Reveal.Property is so that I can hide away the listOfTable3
collection as a protected property. Much neater.
I think that's all correct, my implementation certainly works, but
please note that I have only implemented this for reading data so
far. I haven't attempted to insert new records into any of the
tables. That's where one of these methods may prove better than the
other.
My next post will show the 2 class method as Hudson suggested would be
better.
Boz
> > >http://groups.google.com/group/nhusersandaskthem (using NH xml mappings
But before I start, it's worth noting this solution uses HasManyToMany
in a way which isn't recommended in the NHibernate best practices,
under "Don't use exotic association mappings", indeed it recommends to
use 3 classes instead if there's additional info in the link table:
https://www.hibernate.org/hib_docs/nhibernate/1.2/reference/en/html/best-practices.html
Anyway, assuming you want to do this, and I've yet to determine which
is going to work best for me:
First, modify Table1 from previous post to:
public class Table1 // Table2 similar to Table1
{
public virtual decimal Id {get;set;}
public virtual string Name {get;set;}
public virtual Table2
{
get
{
result listOfTable2[0]; // with collection validation!
}
}
protected virtual IList<Table2> listOfTable2 {get; set;} // hidden
public Table1()
{
listOfTable2 = new List<Table2>();
}
}
and then the mapping:
public class Table1Map : ClassMap<Table1> // Table2Map similar
{
public Table1Map()
{
Table("Table1");
Id(x => x.Id, "Table1_Id");
Map(x => x.Name, "Name");
HasManyToMany<Table2>(Reveal.Property<Table1>("listOfTable2"))
.Table("Table2")
.ParentKeyColumn("Table1_Id")
.ChildKeyColumn("Table2_Id")
.Inverse();
}
}
See my previous post for detail on the protected property and
Reveal.Property helper method.
That too works for me in a read capacity. Haven't tried writing yet.
I think the .Inverse() is correct, would appreciate someone checking
that.
So in summary, if you want to model a one-to-one indirect relationship
with a link table (or two way reference or whatever you call it), it
can be done with either of these two methods. 2 classes certainly
looks neater, but writing data and performance will be the proof of
the pudding. And that NHibernate best practice comment concerns me.
It's been an excellent crash course in NHibernate and Fluent for me,
but I have to warn developers that the lack of documentation on these
features in this scenario has led to a lot of trial and error
learning, and I'm sure there's more work to do on this.
Boz
> > > >http://groups.google.com/group/nhusersandaskthem(using NH xml mappings
To unsubscribe from this group, send email to fluent-nhibern...@googlegroups.com.