This project has moved. For the latest updates, please go here.

Hierarchical collections are broken

Nov 18, 2014 at 10:34 AM
Hi there,

Recently I've updated mongoRepository to the latest version (1.6.6) and it does not process class hierarchy any more. Here is a simple example of that:
public abstract class A:Entity
    {
        public string Prop1 { get; set; }
    }

    public class B : A
    {
        public string Prop2 { get; set; }
    }

    public class C : A
    {
        public string Prop3 { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            BsonClassMap.RegisterClassMap<B>();
            BsonClassMap.RegisterClassMap<C>();

            var repo1 = new MongoRepository<B>("mongodb://localhost/MongoTest")
            {
                new B() {Prop2 = "0"},
            };

            var repo2 = new MongoRepository<C>("mongodb://localhost/MongoTest")
            {
                new C() {Prop3 = "1"},
            };

        }
    }
Instead of creating one collection A it creates B and C
Coordinator
Nov 18, 2014 at 1:46 PM
Are you sure you didn't change any code? I am not aware of any changes in this respect (but I could be mistaken...)

This code makes (more) sense and works as expected:
var repo1 = new MongoRepository<A>("mongodb://localhost/MongoTest")
{
    new B() {Prop2 = "0"},
};

var repo2 = new MongoRepository<A>("mongodb://localhost/MongoTest")
{
    new C() {Prop3 = "1"},
};
Nov 18, 2014 at 2:00 PM
Edited Nov 18, 2014 at 2:00 PM
My code worked in 1.6.1 and stopped in further versions.
Sometimes you have just a type without knowing its base type and need to store\retrieve it from storage. And that was perfectly achieved with 1.6.1

Just try it with 1.6.1 and with 1.6.6, you'll see the difference
Coordinator
Nov 18, 2014 at 2:32 PM
Edited Nov 18, 2014 at 2:34 PM
You can use the CollectionName attribute to decorate class B and C with a collectionname "A". If this used to work in a previous version I assume the implementation on the underlying Mongo C# driver changed somewhere but I'm not sure and can't remember from the top of my head. I'd have to go through the changesets on MongoRepo to be sure; as far as I can remember backwards compatibility hasn't been broken in any recent versions (but I could be mistaken). I am currently swamped with work so I'm afraid I won't be able to do this anytime soon (but I promise to try hard).
Coordinator
Nov 18, 2014 at 2:35 PM
Edited Nov 18, 2014 at 5:09 PM
Hmmm, this one looks promising / related and here's it's related discussion.
Nov 18, 2014 at 2:39 PM
Will be pity to decorate classes / do other stuff as I have ~100 of them using repository via custom query classes. Also i'd like to update mongo driver which I can't due to broken compability.
Thanks for your help and a great product
Coordinator
Nov 18, 2014 at 3:29 PM
Edited Nov 18, 2014 at 3:30 PM
Hmmm; I'll have to look into it a bit deeper then; somehow compatibility has (unknowingly?) been broken I guess. I'll have to see if I can come up with a fix that doesn't break compatibility again ... If you have any ideas on that you're welcome to suggest / make a patch.
Nov 18, 2014 at 3:42 PM
The code you've reffered to seems to do the right job, I just have no idea why it's not working
Nov 18, 2014 at 4:55 PM
Hi
I've taken a look to the issue and found the reason.
The issue appeared between the 1.6.4 and 1.6.5 (in the changeset https://mongorepository.codeplex.com/SourceControl/changeset/32555)

class: Util.cs
the following code has been added
156                 if (entitytype.Equals(typeof(Entity)))
157                 {
158                     // No attribute found, get the basetype
159                     while (!entitytype.BaseType.Equals(typeof(Entity)))
160                     {
161                         entitytype = entitytype.BaseType;
162                     }
163                 }
Which is wrong a bit because derived class type is not equal of base class type. Should be as below:
                if (typeof(Entity).IsAssignableFrom(entitytype))
                {
                    // No attribute found, get the basetype
                    while (!entitytype.BaseType.Equals(typeof(Entity)))
                    {
                        entitytype = entitytype.BaseType;
                    }
                }
Coordinator
Nov 18, 2014 at 5:11 PM
Edited Nov 18, 2014 at 5:14 PM
If Scratch_Net could confirm this fixes the issue I'll commit this change (after a few tests of myself) ASAP. Thank you for looking into it while I was too busy!

EDIT
Hmm, the changeset you're referring to is a merge, which originated in 31654; my earlier suspicions seem to be correct then.
Nov 18, 2014 at 5:25 PM
I confirm that it does fix my problem. Thank you, BugagaController and RobIII
Coordinator
Nov 18, 2014 at 5:51 PM
Edited Nov 18, 2014 at 6:10 PM
See Changeset 35375 and also please confirm my "unittest" matches your case close enough as I did change stuff around a tiny bit (using MongoRepository<ClassA> instead of specific MongoRepository<ClassB> / MongoRepository<ClassC> repo's to ensure the type (_t) is also serialized for later in the test). The test also confirms the "A" repository contains 2 items (one B, one c) and tests specifically for a single B and single C being present.

Also, somehow that code feels dirty anyway; I'm not quite sure why I put that while loop there in the first place and if there's a more efficient way to do what it does (there probably is...). I'll take a look at it again soon. For now, if this fixes your issues I'm (tentatively) fine with it...

Edit
Also if (typeof(Entity) should probably be if (typeof(IEntity) in the proposed patch... (Note the interface IEntity, not the baseclass Entity).

Edit2
Hmmm; that breaks my other unittest "Discussion433878". I really need to sit down and figure this out once and for all instead of trying to hurry a fix. Please allow for a little more time to fix.
Nov 18, 2014 at 6:02 PM
Edited Nov 18, 2014 at 6:14 PM
Yes, I confirm that that's what we need. Thank you very much

EDIT

I'd add MongoRepository<ClassB> entity creation test to ensure it works in both directions
Nov 19, 2014 at 10:57 AM
Hi,
When will we see the new version in nuget?
Coordinator
Nov 19, 2014 at 12:56 PM
As soon as I've had some time to go over my concerns before I break it (again) for others.
Coordinator
Nov 27, 2014 at 1:50 PM
Edited Nov 27, 2014 at 2:26 PM
I just released 1.6.7 with the fix as it was i Changeset 35375

I had to re-publish the 1.6.7 NuGet package as 1.6.7.1 because somehow the resulting version of the DLL's were incorrect.