Linq To Nhibernate: HqlTreeBuilder con elementos ¿cómo usarlo?

Para un proyecto que estoy desarrollando, tengo que usar Linq para crear algunas especificaciones. Ahora tengo un Diccionario en el que tengo que buscar los valores. Dado que la implementación predeterminada de Linq para NHibernate no es compatible con la función ContieneValor, decidí crear la mía.

Así que creé una clase llamada ContieneValueGenerator que deriva de BaseHqlGeneratorForMethod de la siguiente manera:

public class ContainsValueGenerator : BaseHqlGeneratorForMethod
{
    public ContainsValueGenerator()
    {
        SupportedMethods = new[] { ReflectionHelper.GetMethodDefinition(() => new Dictionary<object, object>().ContainsValue(null)) };
    }

    public override HqlTreeNode BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor)
    {
        //Session.CreateQuery("from Message m where 'aDictionaryValue' in elements(m.Dictionary)"); 

        HqlTreeNode hqlTreeNode = treeBuilder.Elements(); // TODO include dictionary here? 
        return treeBuilder.In(visitor.Visit(arguments[0]).AsExpression(), hqlTreeNode);
        //return treeBuilder.In(visitor.Visit(arguments[0]).AsExpression(), treeBuilder.Indices(visitor.Visit(targetObject).AsExpression())); ContainsKey Method implementation 
    }
}

Miré el código fuente de Nhibernate y tomé la implementación del método ContainerKey. La sintaxis de Hql es muy similar a la sintaxis de containskey. Lo único que debe cambiar (supongo) es que, en lugar de treebuilder.Indices(), tengo que usar treebuilder.Elements (que se muestra en los comentarios).

Ahí es donde estoy atascado; No puedo proporcionar ElementsExpression con mi propio diccionario. ¿Cómo puedo crear un HqlTreeNode que aproveche una expresión de Elements?

Gracias de antemano, Rob Van Pamel.

preguntado el 03 de mayo de 12 a las 12:05

1 Respuestas

La solución es crear su propia clase HqlElements que herede de HqlExpression. De hecho, es solo una copia del Índices Hql clase.

public class HqlElements : HqlExpression
{
    public HqlElements(IASTFactory factory, HqlExpression dictionary)
        : base(HqlSqlWalker.ELEMENTS, "elements", factory, dictionary)
    {
    }
}

La parte complicada es agregar esto como propiedad a la HqlTreeBuilder clase. Por lo tanto, puede utilizar un método de extensión. Esto contiene uno feo pieza de código para obtener la fábrica de HqlTreeBuilder con reflexión.

public static class HqlTreeBuilderExtensions
{
    public static HqlElements Elements(this HqlTreeBuilder treeBuilder, HqlExpression dictionary)
    {
        var factory = (IASTFactory) treeBuilder.GetType().GetField("_factory", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(treeBuilder);

        return new HqlElements(factory, dictionary);
    }
}

Su generador ahora se puede cambiar a:

public class ContainsValueGenerator : BaseHqlGeneratorForMethod
{
    public ContainsValueGenerator()
    {
        SupportedMethods = new[] { ReflectionHelper.GetMethodDefinition(() => new Dictionary<object, object>().ContainsValue(null)) };
    }

    public override HqlTreeNode BuildHql(MethodInfo method, Expression targetObject, ReadOnlyCollection<Expression> arguments, HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor)
    {
        return treeBuilder.In(visitor.Visit(arguments[0]).AsExpression(), treeBuilder.Elements(visitor.Visit(targetObject).AsExpression()));
    }
}

La mejor solución sería que este fragmento de código se convirtiera en NHibernate. Tal vez agregue un parche a GitHub para eso.

contestado el 08 de mayo de 12 a las 08:05

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.