Hybrid Class with Mapped and Dynamic Attributes?

May 19, 2015 at 9:41 PM
I have a class defined similarly to below:
public class MyEntity
{
    public string DN { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public IDictionary<string, object> UserDefinedAttributes { get; set;}
}
I can map most of this (DN, Name, Description) no problem. The issue is that these entries in the LDAP can have user-defined auxillary objectclasses such that there's no way for the code to know ahead of time how to map it or what other attributes may be set for the entry. The "UserDefinedAttributes" property is meant as a catch-all such that any unmapped attributes would go in here (similar to the IDirectoryAttributes class).

Basically what I'd like is "map the attributes you know of and stuff everything else in the UserDefinedAttributes property". I didn't see any way to accomplish this with the out-of-the-box code.

Any ideas?

Thanks!
Coordinator
May 21, 2015 at 5:20 AM
Edited May 21, 2015 at 5:23 AM
HI,

Unfortunately you can't mix fixed mapping with dynamic mapping. Depending on the LDAP server you need explicitly ask for attributes in order for them to be returned. You can create helper methods so you can still encapsulate your mapping logic and use dynamic mapping. Here's an example:
public class MyEntity
{
    public static readonly Func<IDirectoryAttributes, MyEntity> Selector = da => new MyEntity
    {
        CommonName = da.GetString("cn"),
        UserId = da.GetString("uid"),
        DN = da.DistinguishedName,
        UserDefinedAttributes = da.Where(x => !new[]{"cn", "uid"}.Contains(x.Key)).ToDictionary(x => x.Key, x => x.Value)
    };

    public string DN { get; set; }

    public string CommonName { get; set; }

    public string UserId { get; set; }

    public IDictionary<string, object> UserDefinedAttributes { get; set; }
}


List<MyEntity> results = _context.Query("...")
                            .ToList()
                            .Select(MyEntity.Selector)
                            .ToList();
Marked as answer by wayne_carson on 5/21/2015 at 6:49 AM
May 21, 2015 at 2:49 PM
Thanks for the quick reply!
Your example is basically what I have in place now...although not nearly as elegant as your solution!

I was also looking at the IObjectMapping/IPropertyMapping interfaces to see if there was any way they could be hacked to provide an "extra attributes" mapping, similar to what MongoDB provides (shown below), but it didn't look doable.
BsonClassMap.RegisterClassMap<MyClass>(cm => 
{
    cm.AutoMap();
    cm.MapExtraElementsMember(c => c.CatchAll);
});
Coordinator
May 21, 2015 at 3:43 PM
That's actually a pretty cool feature. I'll create a ticket for this. Thanks!
Coordinator
May 21, 2015 at 3:44 PM
This discussion has been copied to a work item. Click here to go to the work item and continue the discussion.