Having problems with multiple many-to-many's between two entities

Original Post Chad Myers's Avatar

Chad Myers

05 Mar, 2010 07:05 PM via web

We're working on upgrading our code to the latest NH and FNH. After upgrading, I get an error like this:

System.NotSupportedException: Can't figure out what the other side of the many-to-many property 'Supervisors' should be.

My model is: User entity and Queue entity. A Queue has Supervisors (mtm User) and Users (mtm User). A User has GetSupervisedQueues (mtm to Queue) and GetQueueMemberships (mtm to Queue).

My problem appears to stem from the fact that BiDirectionalManyToManyPairingVisitor has a very specific way it wants to pair the two sides of the MTM.

I understand that if I rename my methods on the User object things will probably work. I was hoping that maybe we could add a convention for this somehow?

To resolve this issue, please guide me to:

1.) Workaround this somehow that doesn't involve me having to rename members on my domain (somewhat painful for me)
-or- 2.) Tell me you'd be happy to accept a patch/pull request for making BiDirectionalManyToManyPairingVisitor more conventional

I don't want to do the work for a pull request if you're going to reject it, so a pre-approval would be helpful at least.

  1. Support Staff 2 Posted by James Gregory on 06 Mar, 2010 12:50 PM

    James Gregory's Avatar

    Well, there's two issues here really.

    1. The pairing logic in the BiDirectionalManyToManyPairingVisitor is crap
    2. When the logic inevitably does fail, it blows up big time

    The former can only be improved so much. I'll never be able to write something that'll be able to catch everything, which makes changing the latter even more important.

    I've committed a change that hopefully improves both scenarios. The logic has been beefed up a lot to do some more intelligent string parsing of the member names to find matches (rather than just checking if the child type is in the collection name). I've also updated the visitor to include a fall-through to a user-defined function for doing the pairing if the logic does fail (instead of throwing an exception as it currently does)

    Another issue that's reared it's head while doing this is that this particular visitor occurs before any conventions are applied. This is because this actual visitor is only doing the pairing of relationships, not actually making any changes to the mappings themselves; once all the relationships have been paired that can be, the conventions are then applied to change table names and what not. This area (stupidly) wasn't really designed with having the user intervene in mind, so it doesn't lend itself well to it. I'm working on that, so what I've done so far isn't as pretty as I would like.

    Your solution should hopefully be:

    1. Update FNH to the latest source, run your tests (or whatever) and see if the new logic has worked (also check it hasn't broken any other cases, though it shouldn't)
    2. If the above hasn't done anything, you'll have to manually associate the offending members. If you need to do that, follow the instructions below:

    Depending on how you're setting up your mappings, whether you're still deriving from PersistenceModel or using the Fluently.Configure stuff, you'd do this differently.

    Deriving from PersistenceModel

    public class MyPM : PersistenceModel
    {
      public MyPM()
      {
        BiDirectionalManyToManyPairer = your_pairer;
      }
    
      private void your_pairer(ICollectionMapping current, IEnumerable<ICollectionMapping> possibles, bool wasResolved)
      {
        // only alter ones that FNH couldn't do
        if (wasResolved) return;
    
        // some logic here to find the right "other side" in possibles
        current.OtherSide = foundOtherSide;
        foundOtherSide.OtherSide = current;
      }
    }
    

    Using Fluently.Configure

    Same deal as above, but use the OverrideBiDirectionalManyToManyPairing method on the FluentMappings property.

    Fluently.Configure()
      .Mappings(m =>
      {
        m.FluentMappings.OverrideBiDirectionalManyToManyPairing(/* see above */);
      });
    

    I'm not really happy with this solution, it's ugly; but it should hopefully work for the time being until I can come up with a better way.

    My first thought is to not have override as a delegate, and that it should be a proper class; however, because it's pre-conventions it wouldn't be a convention, and it'd just be an edge case. This makes me think there's an underlying flaw in the design (obviously), so I need something more long term. That's a discussion for another time though.

    Let me know how you get on.

  2. 3 Posted by Chad Myers on 08 Mar, 2010 11:12 PM

    Chad Myers's Avatar

    James,

    That fixed our issue. Thanks!

  3. 4 Posted by Chad Myers on 08 Mar, 2010 11:13 PM

    Chad Myers's Avatar

    Side note: Brandon my co-worker said: "That's some first-class service James just gave us." Indeed!

  4. Support Staff 5 Posted by James Gregory on 09 Mar, 2010 08:57 AM

    James Gregory's Avatar

    Service with a smile too :)

    Out of interest, did it just start working (ie the smarter logic worked) or did you have to use the manual jig?

  5. 6 Posted by brandonbehrens on 09 Mar, 2010 09:07 PM

    brandonbehrens's Avatar

    The fix worked with no further modifications required. Thanks again!

  6. James Gregory resolved this discussion on 12 Mar, 2010 09:41 AM.

Comments are currently closed for this discussion. You can start a new one.

Recent Discussions

05 Jul, 2010 10:29 PM
05 Jul, 2010 12:45 PM
05 Jul, 2010 12:42 PM
05 Jul, 2010 12:17 PM
05 Jul, 2010 12:12 PM

 

03 Jul, 2010 12:26 AM
02 Jul, 2010 02:17 PM
02 Jul, 2010 08:18 AM
02 Jul, 2010 12:20 AM
01 Jul, 2010 10:14 PM