1

I'm using a modified version of LinqKit in order to have my extensions at one place.

Therefore I have a singel part of each of my entity-classes where I define my expression, e.g. for tblMain:

public partial class tblMain
{
    public static Expression<Func<tblMain, bool>> IsVisible => (e) => e.MainStatus == "Visible";
}

In a query I am now able to write something like this

var visibleEntries = dbContext
    .tblMain
    .AsExpandable()
    .Where(m => tblMain.IsVisible.Invoke(m))
    .ToList();

which will return me all of the visible entries of the table tblMain.

I wondered if there is any way to not have this a static property. This would enable me to use Interfaces like IVisibilityEntity to force a public IsVisible property on specific types.

For now I've ended up with:

public Expression<Func<bool>> IsVisible2 => Expression.Lambda<Func<bool>>(Expression.Invoke(IsVisible, Expression.Variable(typeof(tblMain))));

but this throws me an exception

InvalidOperationException: variable 'm' of type 'tblMain' referenced from scope '', but it is not defined.

Same when using Expression.Constant(this, typeof(tblMain)) as second parameter.

What I would love to have is a query like

var visibleEntries = dbContext
    .tblMain
    .AsExpandable()
    .Where(m => m.IsVisible.Invoke())
    .ToList();

This may seem not that much of a change. But I really want to be able to use the interface-feature to describe my underlying database-model.

With interfaces it also allows checks, e.g. if(myEntity is IVisibilityEntity) to do specific visibility-stuff.

Any ideas if this is possible and how this can be achieved?

Edit 1

As of the first comment. I use LinqKit to enable the same logic for sub-queries:

var visibleEntries = dbContext
    .tblMain
    .AsExpandable()
    .Where(m => tblMain.IsVisible.Invoke(m))
    .Select(m => new
    {
        VisibleSubs = m.tblSub.Where(s => tblSub.IsVisible.Invoke(s)).Select(s => new 
        {
            // ...
        })
    })
    .ToList();

The query above would give me all visible main-entries and their related (and also visible) sub-entries. But this is not possible with simply writing m.tblSub.Where(tblSub.IsVisible) as this shows

CS1929 'ICollection<tblSub>' does not contain a definition for 'Where' and the best extension method overload 'Queryable.Where<tblSub>(IQueryable<tblSub>, Expression<Func<tblSub, bool>>)' requires a receiver of type 'IQueryable<tblSub>'
KingKerosin
  • 3,639
  • 4
  • 38
  • 77
  • In your first snippet you can write `.Where(tblMain.IsVisible)` and then you don't even need LINQKit at all. – Servy Apr 10 '17 at 17:14
  • @Servy I know about this usage. Please see my updated question (`Edit 1`). Also this solution would not solve the interface-issue nor is is suitable for sub-queries. – KingKerosin Apr 10 '17 at 18:07

1 Answers1

0

what about defining your properties like this: https://damieng.com/blog/2009/06/24/client-side-properties-and-any-remote-linq-provider It is essentially property definition in the form of:

partial class Employee {
    private static readonly CompiledExpression<Employee,string> fullNameExpression
     = DefaultTranslationOf<Employee>.Property(e => e.FullName).Is(e => e.Forename + " " + e.Surname);
    private static readonly CompiledExpression<Employee,int> ageExpression
     = DefaultTranslationOf<Employee>.Property(e => e.Age).Is(e => DateTime.Now.Year - e.BirthDate.Value.Year - (((DateTime.Now.Month < e.BirthDate.Value.Month) || (DateTime.Now.Month == e.BirthDate.Value.Month && DateTime.Now.Day < e.BirthDate.Value.Day)) ? 1 : 0)));

  public string FullName {
    get { return fullNameExpression.Evaluate(this); }
  }

  public int Age {
    get { return ageExpression.Evaluate(this); }
  }
}

and the use the Microsoft.Linq.Translations package to resolve.

MBoros
  • 1,090
  • 7
  • 19