简体   繁体   中英

Moving C# function to expression for use in Entity Framework / SQL Select

I have some small C# functions and computed cols from views that I'd like to move to Expressions so that they execute directly against the datasource in native T/SQL.

I can do this inline in the Select, but I'd like to move it to a common function for re-use and testing.

var results = context
    .Products
    .Select(p => new StockDto
    {
        Stock = p.GoodStock - p.LiveStock // Real version is more complex.
    });

I've tried creating a function that returns an expression but C# attempts to assign the expression instead of the result of the expression and won't compile. Using the following Expression variable does not compile either.

public static readonly Expression<Func<DataModel.Product, int>> StockLevel = 
    expr => expr.GoodStock - 10;

I'm familiar with using expressions for appending to Where clauses but I can't figure out how to create an Expression that returns a string from a select statement.

I'd like to do this;

var results = context
    .Products
    .Select(p => new StockDto
    {
        Stock = StockExpression // StockExpression is written in C#
    });

LinqKit seems to be about making predicates (Where clauses) easier to work with, I can't see how to compile an Expression Tree. Is the only way to do this to code a complex expression tree by hand (I'd like to avoid that as it obscures the meaning of the code)?

LinqKit should work for you. You should call Invoke to use one expression in another.

You have two options for "expanding" the merged expressions:

You either invoke AsExpandable on the IQueryable so that it "expands" expressions automatically like this:

var results = context
    .Products
    .AsExpandable()
    .Select(p => new StockDto
    {
        Stock = StockLevel.Invoke(p) 
    });

Or you expand the expression manually before using it like this:

Expression<Func<Product, StockDto>> expression = p => new StockDto
{
    Stock = StockLevel.Invoke(p) 
};

expression = expression.Expand();

var results = context
    .Products
    .Select(expression);

I hope I understood your question, take a look at this discussion. You don't need extra argument, but the idea how to arrange things together might apply to your case.

How to reuse LINQ Select Expression with arguments

private static Expression<Func<Singles, SearchSingles>> CreateSearchSelector()
{
    return s =>
        new SearchSingles
        {
            Foo = foo,
        };
}

// Then use it like this
DataContext.Single.Select(CreateSearchSelector()).ToList();

Look at Microsoft.Linq.Translations . It allows you to define properties with expression trees, and then use them in queries. For select reuse, indeed LinqKit is your friend, or check out this answer, if you really want to understand how it works :)

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