简体   繁体   中英

Generating a LINQ expression in a factory for an NHibernate QueryOver Where clause

I have a data source that supports querying based on several identifiers. These identifiers are abstracted by an IIdentifier class that wraps the type and value for the query. In my NHibernate DAO, I have the following method.

public IEnumerable<ICustomerProfileAttribute> GetCustomerProfileAttributes(
    IIdentifier<CustomerIdentifierTypeEnum> identifier, IEnumerable<string> attributeNames)
{
    IList<ICustomerProfileAttribute> customerProfileAttributes = new List<ICustomerProfileAttribute>();

    ICustomerProfile customerProfileAlias = null;
    ICustomerProfileAttribute customerProfileAttributeAlias = null;
    IEntityTypeAttribute entityTypeAttribute = null;
    IAttribute attributeAlias = null;

    Expression<Func<bool>> findCustomerProfileQuery;
    // I would like to replace the switch with something like this:
    // = FindCustomerProfileExpressionFactory.Get(customerProfileAlias, identifier); 

    switch (identifier.IdentifierType)
    {
        case CustomerIdentifierTypeEnum.CustomerNumber:
            findCustomerProfileQuery = () => customerProfileAlias.CustomerNumber == identifier.Value.ToString();
            break;
        case CustomerIdentifierTypeEnum.WebAccount:
            findCustomerProfileQuery = () => customerProfileAlias.WebAccountId == (long)identifier.Value;
            break;
        case CustomerIdentifierTypeEnum.WebLogin:
            findCustomerProfileQuery = () => customerProfileAlias.LoginEmailAddress == identifier.Value.ToString();
            break;
        default:
            throw new NotImplementedException(String.Format("lookup of customer profiles using {0} is not supported", identifier.IdentifierType));
    }

    return Session.QueryOver(() => customerProfileAttributeAlias)
        .JoinAlias(() => customerProfileAttributeAlias.CustomerProfile, () => customerProfileAlias,
                    JoinType.LeftOuterJoin)
        .Where(findCustomerProfileQuery)
        .JoinAlias(() => customerProfileAttributeAlias.EntityTypeAttribute, () => entityTypeAttribute,
                    JoinType.LeftOuterJoin)
        .JoinAlias(() => entityTypeAttribute.Attribute, () => attributeAlias, JoinType.LeftOuterJoin)
        .Where(Restrictions.On(() => attributeAlias.Name).IsIn(attributeNames.ToArray()))
        .List<ICustomerProfileAttribute>();
}

I would like to extract the switch statement into a factory class, as it would be useful in several other parts of my application. I tried the following:

class FindCustomerProfileExpressionFactory
    {
        static public Expression<Func<bool>> Get(ICustomerProfile profile, IIdentifier<CustomerIdentifierTypeEnum> identifier)
        {
            switch (identifier.IdentifierType)
            {
                case CustomerIdentifierTypeEnum.CustomerNumber:
                    return () => customerProfileAlias.CustomerNumber == identifier.Value.ToString(); 
             ...

However, by referencing the factory class, I am aliasing the local variable into the lambda expression, leading to the following error:

NHibernate.QueryException: could not resolve property: profile of: CustomerProfile.Domain.CustomerProfileAttribute

Is there a way to generate an expression that refers to aa local variable? Could I use a parameterized expression with that Where clause? Any other solutions?

I eventually figured out the answer. It seems as if NHibernate uses the name of the variables in the QueryOver expressions somehow in its code. I changed the parameter name in my factory to match the variable name in the method, and it worked!

QueryOver is not LINQ, so it's much more restricted in the expressions it accepts.

Unless you really need those left joins (I can't tell), I'd probably use LINQ. It will be less convoluted.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM