Filtering against enums stored as strings in LDAP

Apr 18, 2013 at 1:58 AM
Ran into an issue creating LINQ where clause restrictions when the reference property is mapped as an enumeration and the value is stored as a string in the database.

Standard CRUD operations work fine, but queries fail because the LDAP filter created by the expression translator always outputs an integer value, never the name.

For example, the where clause
query.Where(x => x.BusinessCategory == UserBusinessCategory.PeopleSoft);
always outputs
(businessCategory=2)
instead of
(businessCategory=PeopleSoft)
which is required when the value is stored as a string in the database.

I took a look in the source and it appears that the value passed to the FormatValueToFilter function of the EnumPropertyMapping class is always of type integer and that
        public override string FormatValueToFilter(object value)
        {
            return _isStoredAsInt
                ? ((int) value).ToString()
                : value.ToString();
        }
will always return an integer representation. The unit tests all seem to pass the value as an Enum, in which case this would work and which would explain why the test are not failing.

When I update the code as follows, it solves the issue for me.
        public override string FormatValueToFilter(object value)
        {

            return _isStoredAsInt
                ? SafeConvertToInteger(value)
                : SafeConvertToString(value);
        }

        private string SafeConvertToString(object value)
        {
            if (value is string)
                return (string)value;
            else if (value is int?)
                return Enum.GetName(UnderlyingType, value);
            else
                return value.ToString();
        }

        private string SafeConvertToInteger(object value)
        {
            return ((int)value).ToString();
        }
Thanks for the library, it's definitely been a pleasure to work with.

For reference, here is my mapping class for the user object I am querying.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LinqToLdap.Mapping;
using System.Collections.ObjectModel;

namespace BridgeUM.Library
{
    public class User
    {
        public string DistinguishedName { get; set; }
        public string CommonName { get; set; }

        public string GivenName { get; set; }
        public string Surname { get; set; }
        public string DisplayName { get; set; }
        public string EmployeeId { get; set; }
        public string userPassword { get; set; }
        public string BirthDate { get; set; }
        public string SSNSuffix { get; set; }

        public UserBusinessCategory BusinessCategory { get; set; }

        public Collection<string> Email { get; set; }

        public User()
        {
            this.Email = new Collection<string>();
        }

        public bool IsValidEmailToAdd(string emailToAdd)
        {
            if (string.IsNullOrWhiteSpace(emailToAdd))
                return false;
            if (Email.Contains(emailToAdd.Trim()))
                return false;

            return true;

        }
    }

    public class UserMap : ClassMap<User>
    {
        public override IClassMap PerformMapping(string namingContext = null, string objectCategory = null, bool includeObjectCategory = true, IEnumerable<string> objectClasses = null, bool includeObjectClasses = true)
        {
            NamingContext(Config.Ldap.UsersOu);
            ObjectClasses(new string[] { "inetOrgPerson", "organizationalPerson", "top", "person", "barnabasPerson" }, true);
            NamingContext(Config.Ldap.UsersOu);

            DistinguishedName(x => x.DistinguishedName);

            Map(x => x.CommonName).ReadOnly().Named("cn");
            Map(x => x.GivenName).Named("givenName");
            Map(x => x.Surname).Named("sn");
            Map(x => x.DisplayName).Named("displayName");
            Map(x => x.Email).Named("mail");
            Map(x => x.EmployeeId).Named("employeeNumber");
            Map(x => x.userPassword);
            Map(x => x.BirthDate).Named("birthDate");
            Map(x => x.SSNSuffix).Named("ssnSuffix");

            Map(x => x.BusinessCategory).Named("businessCategory");
                 
            return this;
        }
    }
}
Coordinator
Apr 19, 2013 at 12:09 AM
This discussion has been copied to a work item. Click here to go to the work item and continue the discussion.
Coordinator
Apr 23, 2013 at 3:51 AM
Thanks for the detailed explanation and test case! I'm glad that you are getting some use out of this library, as well.