Git Product home page Git Product logo

linqkit's People

Contributors

alexdresko avatar artelk avatar axelheer avatar bardock avatar david-garcia-garcia avatar dependabot[bot] avatar doboczyakos avatar edwardblair avatar fkorak avatar leotsarev avatar logerfo avatar lucasdiogodeon avatar marcelroozekrans avatar rhyous avatar rsuk avatar scottksmith95 avatar sdanyliv avatar stefh avatar tanielianvb avatar tetious avatar theconstructor avatar thorium avatar tiesont avatar virustrinity avatar yuriipovkh avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

linqkit's Issues

Refactor to segregate EntityFramework dependencies

I have found this project extremely useful. However, I was unable to use the nuget package because of the way that the dependencies are packaged.

I'm integrating into an SOA product with very strict rules, in particular data access dependencies may not occur in a business service, only in a data service. To solve this issue, I cloned your repository and divided it into two assemblies LinqKit and LinqKit.EntityFramework. This solved my issue, and others may have the same requirement. I would suggest this to be your default, and update the nuget package accordingly.

.NET Core?

Are there any plans to port this to .NET Core?

Unable to restore packages

Just cloned the repository into Visual Studio 2015, getting the following messages:

C:\Program Files\dotnet\dotnet.exe restore "D:\Projects\LINQKit.vs\restore.dg"
log : Restoring packages for D:\Projects\LINQKit\src\LinqKit\project.json...
log : Restoring packages for D:\Projects\LINQKit\tests\LinqKit.Microsoft.EntityFrameworkCore.Tests\project.json...
log : Restoring packages for D:\Projects\LINQKit\tests\LinqKit.Tests\project.json...
log : Retrying 'FindPackagesByIdAsyncCore' for source 'https://www.myget.org/F/Code52/api/v3/FindPackagesById()?id='dotnet-test-xunit''.
log : Response status code does not indicate success: 404 (Not Found).
log : Retrying 'FindPackagesByIdAsyncCore' for source 'https://www.myget.org/F/Code52/api/v3/FindPackagesById()?id='dotnet-test-xunit''.
log : Response status code does not indicate success: 404 (Not Found).
error: Failed to retrieve information from remote source 'https://www.myget.org/F/Code52/api/v3/FindPackagesById()?id='dotnet-test-xunit''.
error: Response status code does not indicate success: 404 (Not Found).
log : Retrying 'FindPackagesByIdAsyncCore' for source 'https://www.myget.org/F/Code52/api/v3/FindPackagesById()?id='xunit''.
log : Response status code does not indicate success: 404 (Not Found).
error: Failed to retrieve information from remote source 'https://www.myget.org/F/Code52/api/v3/FindPackagesById()?id='dotnet-test-xunit''.
error: Response status code does not indicate success: 404 (Not Found).
log : Retrying 'FindPackagesByIdAsyncCore' for source 'https://www.myget.org/F/Code52/api/v3/FindPackagesById()?id='xunit''.
log : Response status code does not indicate success: 404 (Not Found).
error: Failed to retrieve information from remote source 'https://www.myget.org/F/Code52/api/v3/FindPackagesById()?id='xunit''.
error: Response status code does not indicate success: 404 (Not Found).

I have no idea what I am missing here.

Any help would be greatly appreciated.

PCL Compatibility

LinqKit 1.1.7.3 can be installed in a Profile 7 PCL but 1.1.8 cannot.

Could not install package 'LinqKit 1.1.8'. You are trying to install this package into a project that targets '.NETPortable,Version=v4.5,Profile=Profile7', but the package does not contain any assembly references or content files that are compatible with that framework. For more information, contact the package author.

Using the Linq.Expression.Optimizer with LinqKit in an ASP.NET (MVC) Application

My apologies in advance if this should be posted elsewhere because it's not an issue/enhancement, but I wanted to test out the optimization package mentioned in the Readme.md file by @Thorium, but wasn't exactly sure where the static initilization call needs to be made.

The readme states:

make this static call once before executing your queries (e.g. to your app startup or static class constructor)

Can this call be made once within the application's lifecycle by calling it in the Application_Start() event in my Global.asax.cs or does it need to be made on a per-request basis in the Application_BeginRequest() event?

Compile time error on Expand method in 1.1.7.1 version, Linq To Entities?

I get compile time error in the following code:

var predicate = PredicateBuilder.New<Device>();
predicate = predicate.And(q => !q.MainDeviceId.HasValue);
 var allCountOfDevices = _deviceBusinessObject.SelectCount(predicate.Expand());// Compile time error

but the following works:

Expression<Func<Device, bool>> predicate = PredicateBuilder.New<Device>();
predicate = predicate.And(q => !q.MainDeviceId.HasValue);
 var allCountOfDevices = _deviceBusinessObject.SelectCount(predicate.Expand());

Expression evaluation fails with nullables

Hi,

I have the expression builder method in VB.net

Public Shared Function CreateBaseFilter(Of returnType As PatientVisitBase)(appointmentId As String, patientId As String,
                                                                             visitId As String, waitingRoomId As Integer?,
                                                                             route As String, ticketNumber As Integer?) As ExpressionStarter(Of returnType)
     Dim predicate = PredicateBuilder.[New](Of returnType)(True)
     If Not String.IsNullOrEmpty(appointmentId) Then predicate = predicate.[And](Function(pvl) pvl.AppointmentId = appointmentId)
     If Not String.IsNullOrEmpty(patientId) Then predicate = predicate.[And](Function(pvl) pvl.PatientId = patientId)
     If Not String.IsNullOrEmpty(visitId) Then predicate = predicate.[And](Function(pv) pv.VisitId = visitId)
     If waitingRoomId.HasValue Then predicate = predicate.[And](Function(pvl) **pvl.CentralWaitingRoomId IsNot Nothing AndAlso** pvl.CentralWaitingRoomId = waitingRoomId)
     If Not String.IsNullOrEmpty(route) Then predicate = predicate.[And](Function(pvl) pvl.Route = route)
     If ticketNumber.HasValue Then predicate = predicate.[And](Function(pvl) pvl.TicketNumber = ticketNumber)
     Return predicate
   End Function

Odd thing is that if pvl.CentralWaitingRoomId (int?) is null the predicate evaluation fails if I do not test for a null first (code in bold). This is odd as comparison of nullable types with a null should work.

Any suggestions?

How to accept arguments inside predicate?

Before anything, a little context.

I am used to create filters as extension methods, so I can reuse them.
But when I want to apply filter on Navigation Property, it doesn´t works, then LINQKit comes:

My Old Code:

    public static IQueryable<ARQUITETURA_ARQUIVO> WhereExpired(this IQueryable<ARQUITETURA_ARQUIVO> query, Status s)
    {
        DateTime dataDeveAprovar = DateTime.Now.AddBusinessDays(-1);

        query = from arquivo in query
                where arquivo.ARQ_FL_STATUS == s
                      && arquivo.ARQ_DT_CADASTRO < dataDeveAprovar
                      && arquivo.MyList.Any()
                select arquivo;

        return query;
    }

So I can do this:

        var arquivosDeveAprovar = (from arquivo in context.ARQUITETURA_ARQUIVO.Include(x => x.ABC).WhereExpirouTempoAprovacao(myStatus)
                                   select arquivo).ToList();

But I can´t:

        var solicitacoesComArquivosPendentes = (from sol in context.PortalProjetista_Solicitacao
                                                where sol.ARQUITETURA_ARQUIVO.WhereExpired(myStatus).Any()
                                                select sol).ToList();

Using LinqKit, I can do this:

        var solicitacoesComArquivosPendentes = (from sol in context.PortalProjetista_Solicitacao
                                                where sol.ARQUITETURA_ARQUIVO.Where(Mypredicate).Any()
                                                select sol).ToList();

But how to pass my argument MyStatus to predicate?

I am doing this, but its not ideal:

Mypredicate = CreatePredicateWithArgument(myStatus)

        var solicitacoesComArquivosPendentes = (from sol in context.PortalProjetista_Solicitacao
                                                where sol.ARQUITETURA_ARQUIVO.Where(Mypredicate).Any()
                                                select sol).ToList();

I also can´t inline that method call to CreatePredicateWithArgument

Not able to utilize AsExpandable

I have created an extension method like:

public static GetRows()
        {
            var to_ret = db.TableRows(x=> new TableRowModel(
            {
                TableRowId = x.TableRowId,
                Type = x.Type,
                Name = x.Name,
                CreatedAt = x.CreatedAt,
                ModifiedAt = x.ModifiedAt,
                Enums = x.Enums.AsExpandable.Select(y => y.ToEnumModel())
            });
            return to_ret;
        }

public static EnumModel ToEnumModel(this Enum x)
        {
            var to_ret = new EnumModel()
            {
                CFPId = x.CFPId,
                CreatedAt = x.CreatedAt,
                ModifiedAt = x.ModifiedAt,
            };
            return to_ret;
        }

This gives error saying:

LINQ to Entities does not recognize the method 'System.Linq.IQueryable1[Test.Models.Enum] AsExpandable[Enum](System.Linq.IQueryable1[Test.Models.Enum])' method, and this method cannot be translated into a store expression.

ExpressionVisitor doesn't handle all expression Types

While looking at the code, I found that resharper warned me that the switch statement in:
Visit

didn't handle:
ExpressionType.UnaryPlus
and
ExpressionType.Power

Pretty easy to fix as I believe UnaryPlus is Unary and Power is Binary.

(note I've not actually used them, but wanted to make sure the code handled them)

using AsExpandable() cause AsNoTracking doesn't work.

I'm using EF code first, I worked with detached entities and for updating my entities I used GraphDiff (that works with detached entities), so when I want to load my entities I use AsNoTraking():

 _uow.Repository<WorkCenterCapacity>()
                .FindAllQueryable()
                .Where(/*some criteria*/) 
                .GroupBy(x => x.WorkCenter.Code)
                .AsNoTracking()
                .ToDictionary(x => x.Key, x => x.FirstOrDefault());
//do some changes
// update using graphDiff

It worked correctly and I was be able to update my detached entity using graphDiff.

But, recently I used LINQKit to use Predicate in my query so I changed above query to:

 _uow.Repository<WorkCenterCapacity>()
                .FindAllQueryable()
                .Where(workCenterListCriteria) //predicate
                .AsExpandable()  //<----------- this line cause AsNoTracking doesn't work
                .GroupBy(x => x.WorkCenter.Code)
                .AsNoTracking()
                .ToDictionary(x => x.Key, x => x.FirstOrDefault());
//do some changes
// update using graphDiff

but now when graphDiff wants to update the loaded WorkCenterCapacity entity I get following Error:

A first chance exception of type 'System.InvalidOperationException' occurred in RefactorThis.GraphDiff.dll

Additional information: GraphDiff supports detached entities only at this time. Please try AsNoTracking() or detach your entites before calling the UpdateGraph method

So it seems that AsExpandable cause AsNotracking doesn't work.

Unbounded variable in expanded predicate

Hi, I've come across one bug in the predicate expansion. Here's sample code that demonstrates it:

public class Foo { public Bar bar; }
public class Bar { public bool baz; }

public class Test
{
    public void Run()
    {
        Expression<Func<Foo, Bar>> barGetter = f => f.bar;
        Expression<Func<Bar, bool>> barPredicate = b => b.baz;
        Expression<Func<Foo, bool>> fooPredicate = x => barPredicate.Invoke(barGetter.Invoke(x));
        Expression<Func<Foo, bool>> inception = y => fooPredicate.Invoke(y);

        var expanded = inception.Expand(); // y => x.bar.baz
        var compiled = expanded.Compile(); // throws an InvalidOperationException
    }
}

The problem is, that the expanded predicate contains unbounded variable x instead of y. I use the Compile function just to check whether the predicate is actually built correctly. If you use same name for parameters of fooPredicate and inception, it's really difficult to find out what's wrong with the expanded predicate, since the DebugView of the predicate seems to be ok.

Predicate.Invoke(Predicate.Invoke(..)) does not work

ExpressionExpander.VisitMethodCall; "Invoke"-Resolver (lines 65-85) is not resolving the case that one of the direct arguments in Invoke(..) is a call to another .Invoke.

Example:

System.Linq.Expressions.Expression<Func<string, string[], IEnumerable<string>>> PredicateFoo =
    (par1, par2) => par1.Split(par2, StringSplitOptions.None); // Just some stuff

System.Linq.Expressions.Expression<Func<string, string[], IEnumerable<string>>> PredicateInnerInvoke =
    (par1, par2) => PredicateFoo.Invoke(par1, par2); // Invoke

System.Linq.Expressions.Expression<Func<string, string[], IEnumerable<string>>> PredicateOuterInvoke =
    (par1, par2) => PredicateFoo.Invoke(PredicateInnerInvoke.Invoke(par1, par2).First(), par2); // Invoke(Invoke(..))

var bad = PredicateOuterInvoke.Expand().ToString();
// bad == (par1, par2) => value(xyz+<>c__DisplayClass2).PredicateOuterInvoke.Invoke(par1, par2).First().Split(par2, None)
// There is still a call to .Invoke here; Entity Framework does not know how to handle this
// Expected (no .Invoke anymore):
// good == (par1, par2) => par1.Split(par2, None).First().Split(par2, None)

We resolved this by using the following (very simple & not correct) Expand method:

public static Expression<TDelegate> ExpandEx<TDelegate>(this Expression<TDelegate> expr)
{
    while (expr.ToString().Contains(".Invoke"))
    {
        expr = LinqKit.Extensions.Expand(expr); // Expand will not expand all .Invoke calls, so do it recursively
    }
    return expr;
}

Our real life example:
Predicate1(X) = Get all users where X
Predicate2(X) = Get all users and their deputies from (Get all users where X)
so we are calling Predicate2.Invoke(Predicate1.Invoke(X)) and this fails.

Expand incorrectly handles nested expressions with anonymous type parameters

Here's a test that reproduces the issue:

    public Expression<Func<T, TResult>> GetExpression<T, TResult>(
        T instanceForTypeInference,
        Expression<Func<T, TResult>> expression )
    {
        return expression;
    }

    public void AnonymousTypeParameterTest()
    {
        var anon = new
        {
            Id = 1,
        };

        var getIdExpression = GetExpression( anon, a => a.Id );
        var compareIdExpression = GetExpression( anon, a => getIdExpression.Invoke( a ) == 1 );

        var expanded = compareIdExpression.Expand();

        var areEqual = expanded.Compile().Invoke( anon );

        Assert.Equal( areEqual, true );
    }

With unmodified LinqKit code, this test throws the following exception during the Compile call, indicating that Expand returned an invalid Expression:

System.InvalidOperationException : variable 'a' of type '<>f__AnonymousType0`1[System.Int32]' referenced from scope '', but it is not defined
   at System.Linq.Expressions.Compiler.VariableBinder.Reference(ParameterExpression node, VariableStorageKind storage)
   at System.Linq.Expressions.Compiler.VariableBinder.VisitParameter(ParameterExpression node)
   at System.Linq.Expressions.ParameterExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at System.Linq.Expressions.ExpressionVisitor.VisitMember(MemberExpression node)
   at System.Linq.Expressions.MemberExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at System.Linq.Expressions.ExpressionVisitor.VisitBinary(BinaryExpression node)
   at System.Linq.Expressions.BinaryExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at System.Linq.Expressions.ExpressionVisitor.Visit(ReadOnlyCollection`1 nodes)
   at System.Linq.Expressions.Compiler.VariableBinder.VisitLambda[T](Expression`1 node)
   at System.Linq.Expressions.Expression`1.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at System.Linq.Expressions.Compiler.LambdaCompiler.Compile(LambdaExpression lambda, DebugInfoGenerator debugInfoGenerator)
   at System.Linq.Expressions.Expression`1.Compile()
   at LinqKit.Tests.ExpressionCombinerTest.AnonymousTypeParameterTest() in <redacted>

While researching this issue, I came across this StackOverflow posting:

http://stackoverflow.com/questions/13501437/linq-entities-build-query-at-runtime-the-parameter-is-not-in-scope-linqkit

Which recommends updating the ExpressionExpander.VisitMemberAccess method to be:

    protected override Expression VisitMemberAccess (MemberExpression m)
    {
        // Strip out any references to expressions captured by outer variables - LINQ to SQL can't handle these:
        string typeName = m.Member.DeclaringType.Name;
        bool isAnonymous = typeName.StartsWith("<>f__AnonymousType"),
        isOuter = !isAnonymous && typeName.StartsWith("<>");
        if (isOuter)
            return TransformExpr (m);

        return base.VisitMemberAccess (m);
    }

I verified that the test above does pass with this modification, but I don't understand ExpressionExpander well enough to know if this is a complete fix.

Missing Not() method in Predicate Builder

Great project, but missing the Not() option in the Predicate Builder:

public static Expression<Func<T, bool>> Not<T>(this Expression<Func<T, bool>> expression) { return Expression.Lambda<Func<T, bool>>(Expression.Not(expression.Body), expression.Parameters); }

This can be used for negating the expression for example:

inner = inner.Or (p => p.Description.Contains ("foo")).Not();

selectively apply QueryOptimizer

I would like to apply the QueryOptimizer only on selected queries instead of only being able to globally turn in on or off.

Reason for that is (currently) that Linq.Expression.Optimizer is introducing massive querytree-recompilation to some of my EF 6.x queries using .AsExpandable().
That means that queries which before only took 900ms for the first run (due to compilation) and then only 2ms for any repeated execution now take 900+ms for every single execution, and memory consumption increases and increases...

Apart from this special problem (which I may be able to solve if I understand how to change that strange F# ExpressionOptimizer.reductionMethods thing from C# code) in these days of IOC/DI any static thing is considered bad practice.
My "app" is heavily using multi-threading so setting QueryOptimizer on demand is not an option.

System.Interactive.Async load failure

It appears that the LinqKit.Microsoft.EntityFrameworkCore is attempting to load the System.Interactive.Async assembly of version 1.2 from the GAC. I'm getting a load failure as I have version 3.0 installed in my project as a NuGet package.

Should the LinqKit.Microsoft.EntityFrameworkCore have the System.Interactive.Async as a package dependency instead of referencing the GAC?

=== Pre-bind state information ===
LOG: DisplayName = System.Interactive.Async, Version=1.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
(Fully-specified)
LOG: Appbase =
LOG: Initial PrivatePath = NULL
LOG: Dynamic Base = NULL
LOG: Cache Base = NULL
LOG: AppName =

Calling assembly : LinqKit.Microsoft.EntityFrameworkCore, Version=1.0.1.0, Culture=neutral, PublicKeyToken=null.

LOG: This bind starts in default load context.
LOG: Using application configuration file: C:.vshost.exe.Config
LOG: Using host configuration file:
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config.
LOG: Post-policy reference: System.Interactive.Async, Version=1.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
LOG: GAC Lookup was unsuccessful.
LOG: Attempting download of new URL f/bin/Debug/System.Interactive.Async.DLL.
LOG: Assembly download was successful. Attempting setup of file: \bin\Debug\System.Interactive.Async.dll
LOG: Entering run-from-source setup phase.
LOG: Assembly Name is: System.Interactive.Async, Version=3.0.0.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263
WRN: Comparing the assembly name resulted in the mismatch: Major Version
ERR: The assembly reference did not match the assembly definition found.
ERR: Run-from-source setup phase failed with hr = 0x80131040.
ERR: Failed to complete setup of assembly (hr = 0x80131040). Probing terminated.

ExpressionExpander.VisitMethodCall(..) throws Exception: Cannot cast MethodCallExpressionN to LambdaExpression

I'm basically trying to dynamically construct an expression similar to the one below, where I can use the same comparison function, but where the values being compared can be passed in, since the value is passed from a property 'higher-up' in the query.

var people = People
     .Where(p => p.Cars
        .Any(c => c.Colour == p.FavouriteColour));

I believe I've constructed the query correctly, but the ExpressionExpander.VisitMethodCall(..) method throws the following exception when I try to use it:

"Unable to cast object of type 'System.Linq.Expressions.InstanceMethodCallExpressionN' to type 'System.Linq.Expressions.LambdaExpression'"

In real-world code, using Entity Framework and actual IQueryable<T>, I often get:

"Unable to cast object of type 'System.Linq.Expressions.MethodCallExpressionN' to type 'System.Linq.Expressions.LambdaExpression'"

I've constructed a LinqPad-friendly example of my problem, as simple as I could make it.

void Main()
{
    var strings = new List<Tuple<String, int>>() {
        new Tuple<String, int>("Hello", 4),
        new Tuple<String, int>("World", 2),
        new Tuple<String, int>("Cheese", 20)
    };

    var queryableStrings = strings.AsQueryable();

    // For this example, I want to check which of these strings are longer than their accompanying number.
    // The expression I want to build needs to use one of the values of the item (the int) in order to construct the expression.
    // Basically just want to construct this:
    //      .Where (x => x.Item1.Length > x.Item2)

    var expressionToCheckTuple = BuildExpressionToCheckTuple();

    var result = queryableStrings
        .AsExpandable()
        .Where (s => expressionToCheckTuple.Invoke(s))
        .ToList();
}

public Expression<Func<string, bool>> BuildExpressionToCheckStringLength(int minLength) {

    return str => str.Length > minLength;

}

public Expression<Func<Tuple<string, int>, bool>> BuildExpressionToCheckTuple() {

    // I'm passed something (eg. Tuple) that contains:
    //  * a value that I need to construct the expression (eg. the 'min length')
    //  * the value that I will need to invoke the expression (eg. the string)

    return tuple => BuildExpressionToCheckStringLength(tuple.Item2 /* the length */).Invoke(tuple.Item1 /* string */);

}

If I'm doing something obviously wrong, I'd really appreciate a nudge in the right direction! Thanks.


I've cross-posted this issue to Stack Overflow here: http://stackoverflow.com/q/23629442/590382

Re-Use static Expressions as filter-rules by table

Given the following data-structure I do have 3 tables.

  • tblUser (holding the users of the application)
  • tblRole (the available roles of the application)
  • tblUserRole (the n-to-m relation between users and the roles they have)

A user can have different states, e.g. Blocked, Active and Inactive.

A tblRole-entity has therefore many tblUser entities bound.

For fetching only user of a certain stati, I've added the following to the partial of tblUser

public static Expression<Func<tblUser, bool>> IsActive => (user) => user.Status == "Active";
public static Expression<Func<tblUser, bool>> IsBlocked => (user) => user.Status == "Blocked";
public static Expression<Func<tblUser, bool>> IsInactive => (user) => user.Status == "Inactive";

Now I can query the data like:

var activeUsers = dbContext.tblUser.AsExpandable().Where(tblUser.IsActive).ToArray();

which will get me all active users actually in my database.

The problem is when doing sub-queries - reusing the same logic for filtering e.g. for active users.

var activeRolesUsers = dbContext.tblRole
    .AsExpandable()
    .Select(role => new
    {
        RoleName = role.RoleName,
        ActiveRoleUsers = role.tblUserRole.Select(userRole => userRole.tblUser).Where(user => tblUser.IsActive.Invoke(user))
    })
    .ToArray();

Which should show me all active users in their respective role. Unfortunately, this throws me the exception:

Unable to cast object of type 'System.Linq.Expressions.PropertyExpression' to type 'System.Linq.Expressions.LambdaExpression'.

File: LinqKit.ExpressionExpander.cs
Method: VisitMethodCall
Line: 67

For me it would be even better to write something like:

var activeUsers = dbContext.tblUser.AsExpandable().Where(user => tblUser.IsActive.Invoke(user)).ToArray();

which would enable me to have the filterings separated and always called the same way (DRY) and they can be combined by using && and || inside the Where/Single/Any.

Adding the following lines to TransformExpr in starting at line 119:

var prope = input.Member as PropertyInfo;
if (( field != null && field.FieldType.GetTypeInfo().IsSubclassOf(typeof(Expression))) ||
    (prope != null && prope.PropertyType.GetTypeInfo().IsSubclassOf(typeof(Expression))))
    return Visit(Expression.Lambda<Func<Expression>>(input).Compile()());

now it works as expected.
This code is taken from http://stackoverflow.com/questions/6226129/is-there-a-particular-reason-linqkits-expander-cant-pick-up-expressions-from-f (the last post).

Looking at the code, this is mainly the same as in TryVisitExpressionFunc (only the check field != null missing).

Is there any specific reason why this should not be done? If so, which one? If not, why not adding it?
I know that the code is just a realy dirty hack and I'm willing to know why this feels so and if there are any reasons why it is how it is.

.NET Native Compiler error

Hi,

I'm trying to build a UWP in the release configuration with the .NET Native toolchain, but LINQKit appears to break it. The Compiler breaks as soon as LINQKit is referenced somewhere in the code. It throws the following error:

// Error List window
Internal compiler error: Sequence contains no elements

// Build output window
1>------ Build started: Project: NativeLinqkitTest, Configuration: Release x64 ------
1>  NativeLinqkitTest -> C:\Users\pjura\Desktop\NativeLinqkitTest\NativeLinqkitTest\bin\x64\Release\NativeLinqkitTest.exe
1>  Starting .NET Native compilation
1>  Processing application code
1>C:\Program Files (x86)\MSBuild\Microsoft\.NetNative\x64\ilc\IlcInternals.targets(936,5): error : Internal compiler error: Sequence contains no elements
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

Sadly it doesn't provide any line number or file. The error happens for me when the .NET Toolchain is enabled on both x86 & x64, Targeting any version of Windows 10. The error happens on both the main LINQKit and the EFCore version. LinqKit.Core does not throw this error.

Steps to reproduce:

  1. Create a blank Universal Windows Application project
  2. Add the nuget package for LINQKit or LINQKit.EFCore
  3. Create a new method or override OnNavigatedTo in MainPage.xaml.cs
  4. Write a line of code that will reference LINQKit, e.g.:
IQueryable<string> set = null;
set.AsExpandable();
// OR
var x = PredicateBuilder.New<string>();
  1. Set the project to Release configuration or enable the .NET Native toolchain in the project settings (enabled by default for the Release configuration)
  2. Build the project => You should see the error.

Do you know any workaround?

Otherwise, thanks for LINQKit :)

No way to get SQL TraceString from ExpandableQuery

Hi,
I see that you insist on SQL Profiling to check the SQL running on the db. But with EF IQueryable I have no need to use a specific tool, as I can cast to ObjectQuery and obtain the SQL with ToTraceString (and other info too). It's not so difficult to add this feature to ExpandableQuery. I did this in my LinqKit project

    public interface ExpandableQuery
    {
        ObjectQuery ObjectQuery { get;  }
    }

    public class ExpandableQuery<T> : IQueryable<T>, IOrderedQueryable<T>, IOrderedQueryable, ExpandableQuery

    [...]
    public ObjectQuery ObjectQuery 
    { 
        get
        { 
            return (ObjectQuery)InnerQuery; 
        }
    }

And I use it like this:

var sql = ((ExpandableQuery)result).ObjectQuery.ToTraceString()

When predicate is too long,it throws System.StackOverflowException

var list = Enumerable.Range(0, 2000).Select(t => t.ToString()).ToList();
var predicate = PredicateBuilder.New<MyTable>(false);
using (var context = new MyTestEntities())
{
    context.Database.Log = log => Trace.WriteLine(log);
    foreach (var item in list)
    {
        predicate = predicate.Or(t => t.Name.Contains(item));
    }

    var count = context.MyTables.AsExpandable().Where(predicate).Count();
}

License information

Hi,
Thanks for the great project! I just noticed that the link to the license file on the Nuget Pages seem to be wrong. Also Github does not show the License Type as MIT which would be quite helpful for your users.

Unable to cast object of type 'System.Linq.Expressions.InstanceMethodCallExpressionN' to type 'System.Linq.Expressions.LambdaExpression'

I have a service performing some aggregation which I want make plugable::

public class AverageValueCalculator : IValueCalculator
{
    public decimal? GetValue(IQueryable<Order> orders)
    {
        return orders.Average(o => (decimal?)o.Amount);
    }
}

And here's the query I want to plug this service in:

IQueryable<Order> orders = ordersRepository.GetAll();
var q = from o in orders
        group o by o.OrderDate into g
        select new
        {
            OrderDate = g.Key,
            AggregatedAmount = g.AsQueryable()
                                .Average(x => (decimal?)x.Amount) // here
        };

So I used LinqKit:

Expression<Func<IQueryable<Order>, decimal?>> expression = orders => _calc.GetValue(orders);

var q = from o in orders
        group o by o.OrderDate into g
        select new
        {
            OrderDate = g.Key,
            AggregatedAmount = expression.Compile()(g.AsQueryable())
        };

But it throws an exception:

Unable to cast object of type 'System.Linq.Expressions.InstanceMethodCallExpressionN' to type 'System.Linq.Expressions.LambdaExpression'.
   at LinqKit.ExpressionExpander.VisitInvocation(InvocationExpression iv)
   at LinqKit.ExpressionVisitor.Visit(Expression exp)
   at LinqKit.ExpressionVisitor.VisitExpressionList(ReadOnlyCollection`1 original)
   at LinqKit.ExpressionVisitor.VisitNew(NewExpression nex)
   at LinqKit.ExpressionVisitor.Visit(Expression exp)
   at LinqKit.ExpressionVisitor.VisitLambda(LambdaExpression lambda)
   at LinqKit.ExpressionVisitor.Visit(Expression exp)
   at LinqKit.ExpressionVisitor.VisitUnary(UnaryExpression u)
   at LinqKit.ExpressionVisitor.Visit(Expression exp)
   at LinqKit.ExpressionVisitor.VisitExpressionList(ReadOnlyCollection`1 original)
   at LinqKit.ExpressionVisitor.VisitMethodCall(MethodCallExpression m)
   at LinqKit.ExpressionExpander.VisitMethodCall(MethodCallExpression m)
   at LinqKit.ExpressionVisitor.Visit(Expression exp)
   at LinqKit.Extensions.Expand(Expression expr)
   at LinqKit.ExpandableQueryProvider`1.System.Linq.IQueryProvider.CreateQuery[TElement](Expression expression)
   at System.Linq.Queryable.Select[TSource,TResult](IQueryable`1 source, Expression`1 selector)
   at MyProject.Services.OrderService.<GetInventoryValuesForOrder>d__14.MoveNext()

Is is fixable on my side, or requires investigation on your side? Thanks!

Unable to build the project

Just tried to build/run the project fresh from the .zip file but It won't let me.

I have no idea what I am missing.
Installed Windows 10 SDK which took over one hour and I'm still stuck with the following errors shown by Visual Studio:

NU1001 The dependency mscorlib could not be resolved. project.json 160 and ongoing. It's all related to sl5.

It's my first project using .xproj so I'm pretty sure that there is something missing - but I dont see it.

Any help would be greatly appreciated

Include(...) after AsExpandable()

I suppose it would be great to support this.
I believe the following lines should be added to ExpandableQuery class:

public IQueryable[T] Include(string path)
{
return InnerQuery.Include(path).AsExpandable();
}

casting string to datetime

Hi there,
Can someone please help .
We are trying to use linqkit to cast a string to date but the sql that is being generated does not contain the cast/convert statement.

we tried following the solution posted in #13
but I think it only works for type casting but there is no direct casting from string to date

sample 1:

                                        condition.And(
                                        p => p.JobAttributes.Any()
                                            && p.JobAttributes.Any(a => a.Type == "Date" &&
                                            a.Name.Contains(attrName) &&
                                            DateTime.Parse(a.Value) > DateTime.Parse(value)))

the sql statement generated only contains up to the condition of the Name

Sample 2:

created a static function in the context

public static DateTime? StringToDate(string value)
        {
            if (DateTime.TryParse(value, out var outDateTime))
            {
                return outDateTime;
            }
            return null;
        }

Expression<Func<string, DateTime?>> expressionToDate = attr => Context.StringToDate(attr);
                   condition.And(
                   p => p.JobAttributes.Any()  && 
                            p.JobAttributes.Any(a => a.Type == "Date" &&
                                            a.Name.Contains(attrName) &&
                                            expressionToDate.(a.Value) > Context.StringToDate(value)))

this one works using the inMemoryProvider but when testing this against a database the sql statement also does not include the date conversion and comparison

please advise, how can we get the sql to generate the string to date conversion

thanks

Running FirstOrDefaultAsync with AsExpandable gives the error

Hi Guys I am running following code and gives an error

static Expression<Func<string, bool>> condition = a => a != null;

var expanded = condition.Expand();
var quee = this.riskRepository.Query().AsExpandable().Where(x => expanded.Invoke(x.PurchaseNumber) && x.AMD_Seq_Num == seqNum).FirstOrDefaultAsync();

The provider for the source IQueryable doesn't implement IDbAsyncQueryProvider. Only providers that implement IDbAsyncQueryProvider can be used for Entity Framework asynchronous operations. For more details see http://go.microsoft.com/fwlink/?LinkId=287068.

Whereas this works fine Note using non async method workds fine

var expanded = condition.Expand();
var quee = this.riskRepository.Query().AsExpandable().Where(x => expanded.Invoke(x.PurchaseNumber) && x.AMD_Seq_Num == seqNum).FirstOrDefault();

Nuget issue on OS with case-sensitive filesystem

I've installed the nuget package with monodevelop on linux. But afterwards I was not able to use it as the system was not able to find the package. It seems this is due to the case-sensitive nature of the filesystem and that there is some "mismatch" between certain package id references: at some places "Linq" is used and at others "LINQ". After I renamed all "LINQ" snippets (in filenames and file contents) to "Linq" the package worked like a charm... :-)

queries that use AsExpandable and .ToListAsync() do NOT run asynchronously

I'm running a number of queries that take advantage of .invoke to re-use where clauses as well as select projections.

However, I've found that the ExpandableDBAsyncEnumerator doesn't actually run the queries asynchronously. It forces the expression to be run synchronously.

This is a pretty major issue for me. Has anyone else come across this? Does anyone have a suitable fix?

ie.

public async Task GetObjectAsync()
{
var obj = await dbSet.AsExpandable().FirstOrDefault();
return obj;

}

var t1 = GetObjectAsync();
var t2 = GetObjectAsync();

await Task.WhenAll(t1,t2);

These two calls to getobjectasync will NOT run asynchrounously - they'll only run synchronously.

Any ideas?

AsExpandable() causes "new transaction is not allowed because there are other threads running in the session.."

Before using LINQKit, our program runs okay. After using it, I see the exception "new transaction is not allowed because there are other threads running in the session..", It looks like that AsExpandable() somehow interferes the EntityFramework's transaction management and cause EF not closing the previous transaction before starting a new one.

Note that I'm mixing the use of DbSet.AsExpandable() and EF DbSet.Where(), assuming that they're compatible with each other. Anyone notice the same issue?

True False methods not intuitive

Scott. Nice library. Saved me a ton of time. Even if you didn't start it, thanks for bringing it to GitHub.

I just started using this library. I solved my problem.

I am going to enter a 'usability' issue if you don't mind. There is no bug.

The issue is with the PredicateBuilder.True and PredicateBuilder.False. Those aren't very intuitive. And they are identical except for the return value. But when to use which is confusing and has to be documented.

public static Expression<Func<T, bool>> True<T> () { return f => true; }
public static Expression<Func<T, bool>> False<T> () { return f => false; }

I still am not sure if I understand correctly why there are two. Is seems like this has a few usability problems:

  1. Training issue. You have two ways to create a predicate instead of one. That adds learning curve of which to use for no reason.
  2. True or False don't mean True or False in a query. What do they mean?
  3. The code is not self-documenting or even intuitive at all.

I think True and False mean this:

  • True - Append predicate starting with AND.
  • False - Append predicate starting with OR.

Am I right?

If so, can we improve this?

Obviously, we would have to leave both the True, False calls for backwards compatibility, but wouldn't the usability be easier and more self-documenting to have one method. But they could be marked as deprecated.

Just spitballing here, but we could do something like this:

public enum AppendPredicateWith
{
    Or,
    And
}

Then use that enum to create the predicate.

public static Expression<Func<T, bool>> Create<T> (AppendPredicateWith andOr = AppendPredicateWith.Or) { return f => andOr == AppendQueryWith.And; }

Or AppendPredicateWith.And could be the default.

Now every time PredicateBuilder is called, it is easy to understand and the code reads like what is happening?

PredicateBuilder.Create<Product>(AppendPredicateWith.Or)

The benefits.

  1. The True False objects that have no apparent meaning are replaced with something meaningful.
  2. There aren't two objects to start a predicate anymore.
  3. The code tells you what is happening and is self-documenting.

Have a nice day.

Too much parenthesis leads to stack overflow.

This is a known issue:
If your expression has too much parenthesis (over 500 but under 1000) then LINQKit will fail as StackOverflowException.

For example, if your expression is like this:
condition || (condition || (condition || (condition || (...
each of the parenthesis will generate a recursive call.

Easiest way to reproduce this is to have 1000 conditions in the list and then just the following LINQ-code:

var combined = conditions.Aggregate(Expression.OrElse);

("and" && would also fail)

Workaround is to generate chunks, a list of lists:
(condition || (condition || (condition)))
||
(condition || (condition || (condition)))
||
(condition || (condition || (condition)))
||

For example:

var chunkAmount = 50; //dynamic size would be better, e.g. based on conditions.Length 
var partitons = conditions
            .Select((x, i) => new { Index = i, Value = x })
            .GroupBy(x => x.Index / chunkAmount)
            .Select(x => x.Select(v => v.Value).ToList())
            .Select(e => e.Aggregate(Expression.OrElse))
            .ToList();

var combined = partitons.Aggregate(Expression.OrElse);

missing licensingUrl node from nuspec in .NET45

We are using proget to manage our packages, this looks as the licensingUrl node to see what the licence is, I can see there is a licence.txt file in the repo, but that is not being referenced in the nuspec file?

Cheers,

Luke

Consuming ExpandableQuery w/ Contains(...) leads to multiple Db hits

Stack:
.NET v4.5.2
EntityFramework v6.1.3
LinqKit v1.1.8

In EF, you can compose IQueryables using Contains(...) and the resulting IQueryable will execute in a single Db hit. E.g.:

var query = db.MyModels.Where(m => m.Id < 10).Select(m => m.Id);
db.MyModels.Where(m => query.Contains(m.Id)).ToList();

triggers a query like

SELECT 
    [Extent1].[Id] AS [Id]
    FROM [dbo].[MyModels] AS [Extent1]
    WHERE  EXISTS (SELECT 
        1 AS [C1]
        FROM [dbo].[MyModels] AS [Extent2]
        WHERE ([Extent2].[Id] < 10) AND ([Extent2].[Id] = [Extent1].[Id])
    )

But if the consumed query is a LinqKit ExpandableQuery, this will instead trigger two Db hits:

var query = db.MyModels.AsExpandable().Where(m => m.Id < 10).Select(m => m.Id);
db.MyModels.Where(m => query.Contains(m.Id)).ToList();
SELECT 
    [Extent1].[Id] AS [Id]
    FROM [dbo].[MyModels] AS [Extent1]
    WHERE [Extent1].[Id] < 10
SELECT 
    [Extent1].[Id] AS [Id]
    FROM [dbo].[MyModels] AS [Extent1]
    WHERE [Extent1].[Id] IN (1, 2, 3, 4, 5, 6, 7, 8, 9)

The SQL generated is essentially the same as if you did

var idsList = db.MyModels.Where(m => m.Id < 10).Select(m => m.Id).ToList();
db.MyModels.Where(m => idsList.Contains(m.Id)).ToList();

except that in the latter case, each Db hit is triggered by a separate ToList() call, whereas in the LinqKit case above the same ToList() call triggers both hits.

Also note that the behavior is the same whether or not the consuming query is expandable:

var query = db.MyModels.AsExpandable().Where(m => m.Id < 10).Select(m => m.Id);
db.MyModels.AsExpandable().Where(m => query.Contains(m.Id)).ToList();

triggers the same two Db hits.

See the attached zip file for a VisualStudio solution w/ a minimal repro and an associated SQL Server Profiler trace file.

LinqKitContainsMinimalRepro.zip

I'm working on an EF project where we'd like to be able to use LinqKit in some of our permissions queries. But we frequently consume permissions logic via Contains(...) -- give me all the entities for which the current user has rights and which satisfy some additional filter. Doing this w/ ExpandableQueries produces extra Db hits. Besides the extra hit, we've previously run into performance issues calling Contains on a List as opposed to an IQueryable b/c EF can't use its query plan cache for these queries.

Note that I've tested this w/ LinqKit, not LinqKit.EntityFramework. Are the two functionally equivalent as of v1.1.8?

The source IQueryable doesn't implement IDbAsyncEnumerable

After updating from 1.1.3.1 to 1.1.7, the following error appeared

The source IQueryable doesn't implement IDbAsyncEnumerable. Only sources that implement IDbAsyncEnumerable can be used for Entity Framework asynchronous operations.

The NuGet is used in a class library targeting .Net Plaform 4.5.

What I think I have found out is that the ExpandableQuery does not implement IDbAsyncEnumerable.

I have tried to look at the source code, but the .Net Core thing is something I haven't had time to look into yet.

Performance optimization

Not all use LinqKit for SQL-generation, some just compiles lambdas on the way and then this is not a problem. But many are not compiling lambdas at all, but transferring to other domains, usually SQL.

So, now that it is also quite powerful to produce big lambdas and not hammer the database for each object one by one, some enterprise applications use LinqKit to produce heavy dynamic SQL. Entity Framework has some optimizations but it's a complex tool and not always as good as you would expect. Usually the SQL-clauses are huge!

I think the LinqKit-produced expression trees can be hugely optimized before transferring them to SQL and this way we would produce better SQL. Smaller and hitting db-indexes better. See for details this: https://thorium.github.io/Linq.Expression.Optimizer/tutorial.html#Anonymous-object-replacement
(With this tool you could avoid typical nested selects inside nested selects.)

For this to work, the lambdas we have to assume that the lambdas that you transfer to the SQL wouldn't have side-effects. So this would be a problem:

var res =
   from x in xs
   let y = CallWebService()
   select x+1; // but not y

So, now, we could have multiple options, what do you think:

  1. Not touch LinqKit, it's ready.
  2. Add one more proj-file/package, besides the current ones, something like LinqKit.Optimizer which references this https://thorium.github.io/Linq.Expression.Optimizer (and FSharp.Core) Could be easy win.
  3. Duplicate the code from that package to C#. Create tests that everything is working. Maintain the new complex code.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.