3
votes

My goal is to use NHibernate schema generation along with Fluent NHibernate's automapper to generate my database. I'm having trouble with what I'll call "unidirectional many-to-many relationships."

Many of my entities have localized resources. A single class might look like this:

public class Something {
  public virtual int Id {get; private set;}
  public virtual Resource Title {get;set;}
  public virtual Resource Description {get;set;}
  public virtual IList<Resource> Bullets {get;set;}
}

The Resource class doesn't have any references back; these are entirely unidirectional.

public class Resource {
    public virtual int Id {get; private set;}
    public virtual IList<LocalizedResource> LocalizedResources {get;set;}
    // etc.
}
public class LocalizedResource { // 
    public virtual int Id {get; private set; }
    public virtual string CultureCode {get;set;}
    public virtual string Value {get;set;}
    public virtual Resource Resource {get;set;}
}

Without the IList<Resource>, everything is generated as I'd want -- Resource ID's are in the Title and Description fields. When I add in the IList though, NHibernate adds the field something_id to the Resource table. I understand why it does this, but in this situation it's not a sustainable approach.

What I want is to create a junction table for the bullets. Something like:

CREATE TABLE SomethingBullet (
  Id int NOT NULL PRIMARY KEY IDENTITY(1,1),
  Something_Id int NOT NULL,
  Resource_Id int NOT NULL
)

This way when I add the other twenty-odd entities into the database I won't end up with a ridiculously wide and sparse Resource table.

How do I instruct the Automapper to treat all IList<Resource> properties this way?

2

2 Answers

4
votes

Every many-to-many is in fact composed with one-to-many's in object model. If your relationship doesn't need to be bidirectional, just don't map the second side. The mapping on your mapped side is not affected at all:

HasManyToMany(x => x.Bullets).AsSet();

In this case, NHibernate already knows that it needs to generate the intermediate table.

See also this article for many-to-many tips.

0
votes

:)

The only way I found to make this work with automapping is by constructing your own custom automapping step and replacing the "native" HasManyToManyStep. It's either that or an override, I'm afraid.

I lifted mine off of Samer Abu Rabie, posted here.

The good news is that Samer's code, so far, seems to work flawlessly with my conventions and whatnots, so, once it was in place, it was completely transparent to everything else in my code.

The bad news is that it costs you the ability to have unidirectional one-to-many relationships, as Samer's code assumes that all x-to-many unidirectional relationships are many-to-many. Depending on your model, this may or may not be a good thing.

Presumably, you could code up a different implementation of ShouldMap that would distinguish between what you want to be many-to-many and what you want to be one-to-many, and everything would then work again. Do note that that would require having two custom steps to replace the native HasManyToManyStep, although, again, Samer's code is a good starting point.

Let us know how it goes. :)

Cheers,
J.