Dynamic Query Execution Using Predicate Builder

Posts   
1  /  2
 
    
Seth avatar
Seth
User
Posts: 204
Joined: 25-Mar-2006
# Posted on: 24-Aug-2008 07:34:39   

Hello all! I was wondering if something like a predicate builder would work with LLBLGen. Here is the code I am referring to: http://www.albahari.com/nutshell/predicatebuilder.html I created a method in my service layer that takes an expression that filters out the data. It works fine when I just pass in an expression as a lambda. When I start to use the Predicate builder I get the following:

Exception: System.ArgumentException Message: "Expression of type 'System.Boolean' cannot be invoked" Stack Trace:

at System.Linq.Expressions.Expression.Invoke(Expression expression, IEnumerable1 arguments) at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.GenericExpressionHandler.HandleInvocationExpression( InvocationExpression expressionToHandle) at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.GenericExpressionHandler.HandleExpression(Expression expressionToHandle) at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.QueryExpressionBuilder.HandleExpression(Expression expressionToHandle) at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.QueryExpressionBuilder. HandleBinaryExpressionArithmeticOrBitOperator(BinaryExpression expressionToHandle) at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.GenericExpressionHandler.HandleExpression(Expression expressionToHandle) at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.QueryExpressionBuilder.HandleExpression(Expression expressionToHandle) at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.QueryExpressionBuilder.HandleLambdaExpression(LambdaExpression expressionToHandle) at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.GenericExpressionHandler.HandleExpression(Expression expressionToHandle) at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.QueryExpressionBuilder.HandleExpression(Expression expressionToHandle) at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.QueryExpressionBuilder.HandleWhereExpression(WhereExpression expressionToHandle) at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.GenericExpressionHandler.HandleExpression(Expression expressionToHandle) at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.QueryExpressionBuilder.HandleExpression(Expression expressionToHandle) at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.GenericExpressionHandler.HandleSelectExpression(SelectExpression expressionToHandle, SelectExpression newInstance) at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.GenericExpressionHandler.HandleSelectExpression(SelectExpression expressionToHandle) at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.QueryExpressionBuilder.HandleSelectExpression(SelectExpression expressionToHandle) at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.GenericExpressionHandler.HandleExpression(Expression expressionToHandle) at SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers.QueryExpressionBuilder.HandleExpression(Expression expressionToHandle) at SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProProviderBase.HandleExpressionTree(Expression expression) at SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProProviderBase.Execute(Expression expression) at SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProProviderBase.System.Linq.IQueryProvider.Execute(Expression expression) at SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProQuery1.Execute() at SD.LLBLGen.Pro.LinqSupportClasses.LLBLGenProQuery1.SD.LLBLGen.Pro.LinqSupportClasses .ILLBLGenProQuery.Execute[TResult]() at TrackerPlus.Business.Views.VehicleView.GetVehiclesByExpression(Expression1 whereClause) in C:\Projects\TrackerPlus\TrackerPlus.Business\Views\VehicleView.cs:line 46 ... my stuff that calls your stuff was here

I am using v2.6 Final, Released on June 6th, 2008. Targeting .NET 3.5 adapter model.

Is there a different way of doing this? I also tried the following variant of the And<> extension method with the following result:

        public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expr1,
                                                             Expression<Func<T, bool>> expr2)
        {
            //var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
            return Expression.Lambda<Func<T, bool>>
                  (Expression.And(expr1.Body, expr2.Body), expr1.Parameters);
        }

Exception: ORMQueryExecutionException InnerException: An object or column name is missing or empty. For SELECT INTO statements, verify each column has a name. For other statements, look for empty alias names. Aliases defined as \"\" or [] are not allowed. Add a name or single space as the alias name. QueryExecuted:

Query: SELECT DISTINCT [LPLA_1].[VehicleId], [LPLA_1].[VIN] AS [Vin], [LPLA_1].[VehicleStatusId], [LPLA_1].[StickerNumber], [LPLA_1].[VehicleNumber], [LPLA_1].[Description], [LPLA_1].[MakeId], [LPLA_1].[ModelId], [LPLA_1].[Year], [LPLA_1].[VehicleTypeId], [LPLA_1].[OwnedBy], [LPLA_1].[AssignedTo], [LPLA_1].[LessorId], [LPLA_1].[LeaseNumber], [LPLA_1].[LeaseYears], [LPLA_1].[LeaseStart], [LPLA_1].[LeaseExpiration], [LPLA_1].[LeaseMiles], [LPLA_1].[PurchasePrice], [LPLA_1].[Residual], [LPLA_1].[LeasePayment], [LPLA_1].[LeaseEndCharge], [LPLA_1].[EmployeeAssigned], [LPLA_1].[PolicyRemovalDate], [LPLA_1].[RegistrationDate], [LPLA_1].[ExpirationDate], [LPLA_1].[DecalWeight], [LPLA_1].[PurchaseDate], [LPLA_1].[PlateNumber], [LPLA_1].[StateCode], [LPLA_1].[RegAddress], [LPLA_1].[RegCity], [LPLA_1].[RegZip], [LPLA_1].[FuelTypeId], [LPLA_1].[Created], [LPLA_1].[Updated], [LPLA_1].[AddedToPolicy]
FROM [dbo].[Vehicle] [LPLA_1]  WHERE ( ( ( ( ( [].[LPFA_1] = @LPFA_11)))))
Parameter: @LPFA_11 : Boolean. Length: 0. Precision: 0. Scale: 0. Direction: Input. Value: True.

My Service Layer call:

public EntityCollection<VehicleEntity> GetVehiclesByExpression(Expression<Func<VehicleEntity, bool>> whereClause)
{
      using (IDataAccessAdapter adapter = this._adapter.Create())
      {
            LinqMetaData metaData = new LinqMetaData(adapter);
            return metaData.Vehicle
                  .Where<VehicleEntity>(whereClause)) as ILLBLGenProQuery)
                  .Execute<EntityCollection<VehicleEntity>>())
      }
}

I do some prefetching of other related entities but ommitted that code to simplify the question. Any thoughts?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 24-Aug-2008 12:23:26   

Don't use the predicate builder, it's using Invoke which is simply hte same as calling a delegate in-memory, which isn't what you want you want the predicate to end up in the db query. The problem is that the 'Invoke' means calling the compiled code, but that's not what's meant: the data inside the expression invoked has to be converted.

I also don't have a clear overview of what is wrong exactly in your second part of the post: please provide the info so we can try to reproduce what you have.

Also, please specify why you do what you are doing, and why you can't use normal linq constructs with linq to llblgen pro which do work.

Frans Bouma | Lead developer LLBLGen Pro
Seth avatar
Seth
User
Posts: 204
Joined: 25-Mar-2006
# Posted on: 25-Aug-2008 17:01:37   

I am doing a report builder with custom predicates. I don't want you to use up too much time working this out because I know how to get it done using the standard LLBLGen predicate system. I just wanted to know if there was something that could be done similar to the predicate builder but in LLBLGen. Again, I've already got it working using the wonderful predicate builder that Linq to LLBLGen is built on top of. It was more of a curiosity thing. The first example showed how the predicate builder does not work. The second was my attempt at building the expression in a different way using my own stuff.

Thanks.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 26-Aug-2008 11:19:22   

No problem Seth simple_smile

I'll see if I can get it to work and if not, what it does behind the scenes to the expression trees so I have a better overview and if I have to add something to make it work simple_smile

Frans Bouma | Lead developer LLBLGen Pro
Antonio avatar
Antonio
User
Posts: 67
Joined: 09-Oct-2007
# Posted on: 28-Aug-2008 11:14:32   

Otis wrote:

No problem Seth simple_smile

I'll see if I can get it to work and if not, what it does behind the scenes to the expression trees so I have a better overview and if I have to add something to make it work simple_smile

Any news? I'm also trying to build a dynamic predicate system, to combine expression with and/or.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 28-Aug-2008 12:28:14   

No news, the planning is that we'll do some in depth testing today.

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 28-Aug-2008 14:22:29   

It simply chokes on the InvocationExpression instances created by the predicatebuilder. Frankly I have no idea why they create these expressions, it might be something that works just with linq to sql which might deal with the invocationexpressions.

I'll spend a brief moment checking whether I can either change the predicatebuilder source or add some support for invocationexpressions in this case, but you all have to realize that this is very very very frustrating. We spend 9 months full time writing a linq provider without any documentation whatsoever, and figuring out how 3rd party software works on linq to sql so we can copy the behavior on our own framework is therefore a matter of tedious trial/error and that added to the countless times we already had to use that way of doing software engineering with linq and expression trees, it's getting a bit too much. We did our very best to provide the best 3rd party linq provider out there, but I have to say there's a limit to what we can do.

The invocationexpression instances in the tree apparently have to be converted into something, as the predicate expression IS created but the handler of the invocationexpression of that produced predicateexpression gives the error in the generic sourcecode for visiting expression trees: the FilterExpression (derived from Expression) isn't invokable because it's not an Expression<T> class.

Anyone who knows WHY on earth this doesn't work, please step forward.

(btw, the predicatebuilder contains 2 bugs as well, 'And' should be 'AndAlso' and 'Or' should be 'OrElse', because 'Or' is a bitwise or operator predicate. )

(edit). The invoke is apparently used to replace parameters in the rightside expression (expr2) with the parameters of expr1. I can do that differently. it now produces a query, but the alias is wrong due to the wrong parameter. The utility class 'ExpressionReplacer' in the linq provider will help simple_smile )

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 28-Aug-2008 14:41:33   

Works.


[Test]
public void GetCustomersUsingPredicateBuilder()
{
    var predicate = PredicateBuilder.Null<CustomerEntity>();

    using(DataAccessAdapter adapter = new DataAccessAdapter())
    {
        LinqMetaData metaData = new LinqMetaData(adapter);
        predicate = predicate.Or(c => c.City == "London");
        predicate = predicate.Or(c => c.City == "Paris");

        var q = metaData.Customer.Where(predicate);

        foreach(var v in q)
        {
            Assert.IsTrue((v.City == "London") || (v.City == "Paris"));
        }
    }
}

New predicate builder class:


public static class PredicateBuilder
{
    public static System.Linq.Expressions.Expression<Func<T, bool>> Null<T>() { return null; }

    public static System.Linq.Expressions.Expression<Func<T, bool>> Or<T>(this System.Linq.Expressions.Expression<Func<T, bool>> expr1,
                                                        System.Linq.Expressions.Expression<Func<T, bool>> expr2)
    {
        if(expr1 == null)
        {
            return expr2;
        }
        ExpressionReplacer replacer = new ExpressionReplacer(CreateFromToReplaceSet(expr2.Parameters, expr1.Parameters), null, null, null, null);
        LambdaExpression rightExpression = (LambdaExpression)replacer.HandleExpression(expr2);
        
        return System.Linq.Expressions.Expression.Lambda<Func<T, bool>>
              (System.Linq.Expressions.Expression.OrElse(expr1.Body, rightExpression.Body), expr1.Parameters);
    }

    public static System.Linq.Expressions.Expression<Func<T, bool>> And<T>(this System.Linq.Expressions.Expression<Func<T, bool>> expr1,
                                                         System.Linq.Expressions.Expression<Func<T, bool>> expr2)
    {
        if(expr1 == null)
        {
            return expr2;
        }
        ExpressionReplacer replacer = new ExpressionReplacer(CreateFromToReplaceSet(expr2.Parameters, expr1.Parameters), null, null, null, null);
        LambdaExpression rightExpression = (LambdaExpression)replacer.HandleExpression(expr2);
        return System.Linq.Expressions.Expression.Lambda<Func<T, bool>>
              (System.Linq.Expressions.Expression.AndAlso(expr1.Body, rightExpression.Body), expr1.Parameters);
    }


    private static Dictionary<LinqExpression, LinqExpression> CreateFromToReplaceSet(IList<ParameterExpression> from, 
                                        IList<ParameterExpression> to)
    {
        Dictionary<LinqExpression, LinqExpression> toReturn = new Dictionary<LinqExpression, LinqExpression>();
        for(int i = 0; i < from.Count; i++)
        {
            toReturn.Add(from[i], to[i]);
        }
        return toReturn;
    }
}


required usings using LinqExpression = System.Linq.Expressions.Expression; using SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers;

**Please let me know if this works for you. **

Sorry for the whining in my previous post, though it sometimes get on my nerves how shabby the whole documentation around everything linq is... disappointed

I did a wild guess with the lambda changes and it worked out ok. haven't tested it further.

You see that it doesn't have True/False methods anymore, this is because those would result in a constant bool as predicate, which isn't supported.

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 01-Sep-2008 18:13:12   

No-one who wants to give a reply?

Frans Bouma | Lead developer LLBLGen Pro
Seth avatar
Seth
User
Posts: 204
Joined: 25-Mar-2006
# Posted on: 01-Sep-2008 19:52:38   

Sorry! I will look at it (this week).

Antonio avatar
Antonio
User
Posts: 67
Joined: 09-Oct-2007
# Posted on: 02-Sep-2008 01:17:48   

Otis wrote:

No-one who wants to give a reply?

It works for me! Now I have a method that combines (with AND/OR) several filter criteria to search articles:


public static IQueryable GetArticoliUsingPredicateBuilder(DataAccessAdapter adapter, LogicalOperator op,
            string codice, 
            string descrizione,
            int? idCategoria,
            int? idProduttore,
            int? idLineaProdotto,
            int? idFornitore,
            bool soloAttivi)
        {
            var predicate = PredicateBuilder.Null<Genio.Data.Adapter.EntityClasses.ArticoliEntity>();

            Genio.Data.Adapter.Linq.LinqMetaData metaData = new Genio.Data.Adapter.Linq.LinqMetaData(adapter);

            if (!String.IsNullOrEmpty(codice))
            {
                if (op == LogicalOperator.Or)
                {
                    predicate = predicate.Or(a => a.CodiceArticolo.Contains(codice) || a.CodiceFornitore.Contains(codice) || a.CodiceAbarre.Contains(codice)).Or(
                        art => art.BarcodeArticolo.Any(
                            bc => bc.Barcode.Contains(codice)));        
                 }
                else predicate = predicate.And(a => a.CodiceArticolo.Contains(codice) || a.CodiceFornitore.Contains(codice) || a.CodiceAbarre.Contains(codice)).Or(
                    art => art.BarcodeArticolo.Any(
                        bc => bc.Barcode.Contains(codice)));

            }

            if (!String.IsNullOrEmpty(descrizione))
            {
                if (op == LogicalOperator.Or)
                    predicate = predicate.Or(a => a.DescrizioneBreve.Contains(descrizione) || a.DescrizioneEstesa.Contains(descrizione));
                else predicate = predicate.And(a => a.DescrizioneBreve.Contains(descrizione) || a.DescrizioneEstesa.Contains(descrizione));
            }

            if (idCategoria.HasValue)
            {
                if (op == LogicalOperator.Or)
                    predicate = predicate.Or(a => a.IdcategoriaArticolo == idCategoria);
                else predicate = predicate.And(a => a.IdcategoriaArticolo == idCategoria);
            }

            if (idProduttore.HasValue)
            {
                if (op == LogicalOperator.Or)
                    predicate = predicate.Or(a => a.Idproduttore == idProduttore);
                else predicate = predicate.And(a => a.Idproduttore == idProduttore);
            }

            if (idLineaProdotto.HasValue)
            {
                if (op == LogicalOperator.Or)
                    predicate = predicate.Or(a => a.IdlineaProdotto == idLineaProdotto);
                else predicate = predicate.And(a => a.IdlineaProdotto == idLineaProdotto);
            }

            if (idFornitore.HasValue)
            {
                if (op == LogicalOperator.Or)
                    predicate = predicate.Or(a => a.IdclienteFornitorePrincipale == idFornitore);
                else predicate = predicate.And(a => a.IdclienteFornitorePrincipale == idFornitore);
            }

            if(soloAttivi)
                predicate = predicate.And(a => a.ArticoloAttivo == true && a.VirtualDeleted == false);
            else predicate = predicate.And(a => a.VirtualDeleted == false);


            PrefetchPath2 pp2 = new PrefetchPath2(EntityType.ArticoliEntity);
            pp2.Add(ArticoliEntity.PrefetchPathBarcodeArticolo);

            var q = metaData.Articoli.Where(predicate).WithPath(pp2).IncludeFields(
              art => art.Idarticolo,
              art => art.CodiceArticolo,
              art => art.DescrizioneBreve,
              art => art.CodiceAbarre,
              art => art.CodiceFornitore,
              art => art.Idproduttore,
              art => art.IdclienteFornitorePrincipale,
              art => art.IdcategoriaArticolo,
              art => art.IdlineaProdotto,
              art => art.ArticoloAttivo);
            
            return q;
        }

thanks

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 02-Sep-2008 11:55:41   

great! smile

Frans Bouma | Lead developer LLBLGen Pro
Posts: 4
Joined: 09-Sep-2008
# Posted on: 09-Sep-2008 07:45:52   

Thank you, Otis! It is really cool sunglasses

Posts: 2
Joined: 10-Sep-2008
# Posted on: 10-Sep-2008 15:13:10   

Hi there

I'm Joe, the guy who wrote PredicateBuilder.

Regarding InvocationExpressions, they're simply a way of calling another lambda expression. It shouldn't be hard to support that within your LINQ parser. Having said that, Entity Framework can't handle InvocationExpressions either, so maybe you're in good company (actually I'd argue you could in bad company wink but that's another story).

Cheers

Joe

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 11-Sep-2008 15:55:55   

joealbahari wrote:

Hi there

I'm Joe, the guy who wrote PredicateBuilder.

Regarding InvocationExpressions, they're simply a way of calling another lambda expression. It shouldn't be hard to support that within your LINQ parser. Having said that, Entity Framework can't handle InvocationExpressions either, so maybe you're in good company (actually I'd argue you could in bad company wink but that's another story).

Cheers

Joe

Hi Joe!

We do have support for them for some cases but not for the case you used them for. Indeed, adding support for them isn't that hard per se, the thing is that they might end up in various situations so figuring out all situations are covered is a different matter, unfortunately.

Luckily it didn't take that long to rewrite your idea to make it work on our code simple_smile Thanks for the initial class! simple_smile

Frans Bouma | Lead developer LLBLGen Pro
Seth avatar
Seth
User
Posts: 204
Joined: 25-Mar-2006
# Posted on: 19-Oct-2008 05:54:49   

Otis: You are free to call me a loser (after all I said I would look at it like forever ago) because I finally got around to using the predicate builder and it works like a charm. I think stylistically it is a bit more aesthetically pleasing. Thanks for the good work!

pat
User
Posts: 215
Joined: 02-Mar-2006
# Posted on: 07-Feb-2009 02:59:04   

Otis wrote:

New predicate builder class:

Cool... maybe this could even become part of the LLBLGen Linq support assemblies?

Thanks, Patrick

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 07-Feb-2009 10:35:12   

pat wrote:

Otis wrote:

New predicate builder class:

Cool... maybe this could even become part of the LLBLGen Linq support assemblies?

Thanks, Patrick

It's indeed a good idea to add this to the lib.

Frans Bouma | Lead developer LLBLGen Pro
hypo
User
Posts: 34
Joined: 14-Oct-2008
# Posted on: 09-Apr-2009 11:31:31   

Hi all,

I wanted to implement the Predicate Builder class, but I can't resolve the LinqExpression type

private static Dictionary<LinqExpression, LinqExpression> CreateFromToReplaceSet(

I have included the 2 dll's and placed the usings.

Please help wink

Kind regards, Wim

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 09-Apr-2009 11:39:26   

add using LinqExpression = System.Linq.Expressions.Expression;

at the top of the file, as our runtime lib also contains an Expression type.

Frans Bouma | Lead developer LLBLGen Pro
Antonio avatar
Antonio
User
Posts: 67
Joined: 09-Oct-2007
# Posted on: 09-Apr-2009 11:42:30   

hypo wrote:

Hi all,

I wanted to implement the Predicate Builder class, but I can't resolve the LinqExpression type

private static Dictionary<LinqExpression, LinqExpression> CreateFromToReplaceSet(

I have included the 2 dll's and placed the usings.

Please help wink

Kind regards, Wim

try adding:


using LinqExpression = System.Linq.Expressions.Expression;

edit: Otis is faster than me!sunglasses

hypo
User
Posts: 34
Joined: 14-Oct-2008
# Posted on: 09-Apr-2009 12:01:24   

Otis wrote:

required usings using LinqExpression = System.Linq.Expressions.Expression; using SD.LLBLGen.Pro.LinqSupportClasses.ExpressionHandlers;

I should start reading the posts a bit better stuck_out_tongue_winking_eye

Still thanks to both for the quick and correct reply wink

Kind regards, Wim

carni4
User
Posts: 20
Joined: 09-Aug-2010
# Posted on: 03-Sep-2010 17:04:55   

Hi there. Is there any advantage to using the Predicate Builder over say, doing something like the following?


using (DataAccessAdapter adapter = new DataAccessAdapter())
            {
                LinqMetaData meta = new LinqMetaData(adapter);

                var involvedParties = from ip in meta.InvolvedParty
                                                       select ip;

                if (timeZoneID.HasValue)
                    involvedParties = involvedParties.Where(ip => ip.Contact.TimeZoneID == timeZoneID.Value);

                if (stateID.HasValue)
                    involvedParties = involvedParties.Where(ip => ip.Contact.City.CountryStateID == stateID.Value);

                if (specialtyID.HasValue)
                    involvedParties = involvedParties.Where(ip => ip.SpecialtyID == specialtyID.Value);

                if (!string.IsNullOrEmpty(zipCode))
                    involvedParties = involvedParties.Where(ip => ip.Contact.ZipCode == zipCode);

                var data = from ip in involvedParties
                           select new
                           {
                               ip.InvolvedPartyID,
                               ip.Contact.CompanyName,
                               ip.IsAutoApprovedClient
                           };

                return data.ToList();
            }

Since the above code works just fine (and runs just a single SQL statement on the server, without any client side filtering), I'm unclear as to why I should consider using the Predicate Builder at the moment. Thanks in advance for the advice.

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 03-Sep-2010 23:44:42   

carni4 wrote:

Since the above code works just fine (and runs just a single SQL statement on the server, without any client side filtering), I'm unclear as to why I should consider using the Predicate Builder at the moment. Thanks in advance for the advice.

You can take advantage of PredicateBuilder (IMHO) if you need to isolate the predicate for any reason (you receive the predicate in a fetch method, or you need to pass the predicate over the wire, or your method does know nothing about the filter parameters and it have to call other method to obtain the predicate). In such cases you could consider use it. Consider the following code:

public void GetCustomersUsingPredicateBuilder()
{
    var predicate = PredicateBuilder.Null<CustomerEntity>();

    using(DataAccessAdapter adapter = new DataAccessAdapter())
    {
        LinqMetaData metaData = new LinqMetaData(adapter);
        predicate = predicate.Or(c => c.City == "London");
        predicate = predicate.Or(c => c.City == "Paris");

        var q = metaData.Customer.Where(predicate);

        foreach(var v in q)
        {
            Assert.IsTrue((v.City == "London") || (v.City == "Paris"));
        }
    }
}

Note that predicate is independent, you use it just in the metaData.Customer.Where(predicate) line.

David Elizondo | LLBLGen Support Team
carni4
User
Posts: 20
Joined: 09-Aug-2010
# Posted on: 07-Sep-2010 17:22:05   

Ok, fair enough; that makes sense. However, for cases that don't require a separate object that can be passed around, is there by chance any difference in performance, the SQL that is output, or how the LINQ/ORM engine handles it?

Most importantly: I want to make sure that I'm not taking advantage of any sort of unsupported behavior that might break in a future release of LLBLGen. I mean, I was wondering why I hadn't seen any similar examples posted by other people. When I search on LLBLGen for 'conditional parameters in a LINQ where clause' (or similar search query) the only thing I can find is the PredicateBuilder, and I wanted to see if there is a good reason for that. The last thing I want to do is write a bunch of LINQ queries my way because it works now, only to find out that this breaks later because I was doing something not supported officially by LLBLGen.

1  /  2