Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create API in Remote.Linq.EntityFrameworkCore to get query result without mapping to DynamicObject #130

Closed
megafetis opened this issue Jun 8, 2024 · 4 comments
Assignees

Comments

@megafetis
Copy link

Hello/ Thanks for great lib. Can you add API in Remote.Linq.EntityFrameworkCore to get query result without mapping to DynamicObject?
In my case i need to handle query result before send to a client. Now i have to convert dynamic object to an target object, and than convert it back to DynamicObject. I think its excess overhead.
May be:

//var resp = await expression.ExecuteWithEntityFrameworkCoreAsync(ctx, HttpContext.RequestAborted);
var obj = await expression.ResultWithEntityFrameworkCoreAsync(ctx, HttpContext.RequestAborted);

// .. some work with obj

return new Aqua.Dynamic.DynamicObjectMapper().MapObject(obj);
@megafetis
Copy link
Author

Edit:
In addition, add useful API for get IQueryable object for manual prepare (Some limitations, mutations)

@6bee 6bee self-assigned this Jun 9, 2024
@6bee
Copy link
Owner

6bee commented Jun 9, 2024

  1. There are various method overloads allowing to provide a Func<Type, IQueryable> queryableProvider argument in place of a DbContext, which allows using custom logic to to resolve and amend the IQueryable to be used.

  2. These extension methods also exist as generic variants, which return the result as the original result type. For working with various types, object can be specified as generic argument.
    E.g. object result = await expression.ExecuteWithEntityFrameworkCoreAsync<object>(ctx)

  3. For further customization of query execution, you may want to update to RL v7.3.0-alpha-001 and either create your own "execution decorator" or make use of the "fluent API".
    Either way, you have the option of returning data converted into DynamicObject or any other data type of your choice by specifying a generic type argument accordingly.

Fluent API

return await expression.EntityFrameworkCoreExecutor(efContext)
    .With(PrepareRemoteLinqExpressionStrategy)
    .With(PrepareSystemLinqExpressionStrategy)
    .With(ProcessExecutionResultsStrategy)
    .With(ProcessDynamicObjectResultsStrategy)
    .ExecuteAsync(cancellation);

static Remote.Linq.Expressions.Expression PrepareRemoteLinqExpressionStrategy(Remote.Linq.Expressions.Expression exp)
    => exp;

static System.Linq.Expressions.Expression PrepareSystemLinqExpressionStrategy(System.Linq.Expressions.Expression exp)
    => exp;

static object ProcessExecutionResultsStrategy(object result)
    => result;

static DynamicObject ProcessDynamicObjectResultsStrategy(DynamicObject result)
    => result;

Execution Decorator

var executor = expression.EntityFrameworkCoreExecutor(efContext);
var decorator = new CustomExpressionExecutionDecorator(executor);
return await decorator.ExecuteAsync(cancellationToken);
private sealed class CustomExpressionExecutionDecorator : AsyncExpressionExecutionContext<DynamicObject>
{
    public CustomExpressionExecutionDecorator(AsyncExpressionExecutionContext<DynamicObject> parent)
        : base(parent)
    {
    }

    protected override Expression Prepare(Expression expression)
    {
        // used for synchronous and asynchronous execution
        return base.Prepare(expression);
    }

    protected override System.Linq.Expressions.Expression Transform(Expression expression)
    {
        // used for synchronous and asynchronous execution
        return base.Transform(expression);
    }

    protected override System.Linq.Expressions.Expression Prepare(System.Linq.Expressions.Expression expression)
    {
        // used for synchronous and asynchronous execution
        return base.Prepare(expression);
    }

    protected override System.Linq.Expressions.Expression PrepareAsyncQuery(System.Linq.Expressions.Expression expression, CancellationToken cancellation)
    {
        // used for asynchronous execution only
        return base.PrepareAsyncQuery(expression, cancellation);
    }

    protected override object Execute(System.Linq.Expressions.Expression expression)
    {
        // used for synchronous execution only
        return base.Execute(expression);
    }

    protected override ValueTask<object> ExecuteAsync(System.Linq.Expressions.Expression expression, CancellationToken cancellation)
    {
        // used for asynchronous execution only
        return base.ExecuteAsync(expression, cancellation);
    }

    protected override object ProcessResult(object queryResult)
    {
        // used for synchronous and asynchronous execution
        return base.ProcessResult(queryResult);
    }

    protected override DynamicObject ConvertResult(object queryResult)
    {
        // used for synchronous and asynchronous execution
        return base.ConvertResult(queryResult);
    }

    protected override DynamicObject ProcessConvertedResult(DynamicObject queryResult)
    {
        // used for synchronous and asynchronous execution
        return base.ProcessConvertedResult(queryResult);
    }
}

@megafetis
Copy link
Author

Cool, thank s. It will resolve my case and more

@megafetis
Copy link
Author

I am delighted with the capabilities of this library in conjunction with the Blazor web assembly. I have implemented data requests almost to the end. This mechanism should experimentally replace GraphQL with the exception of database modification operations. It remains for security purposes to get an IQueryable object associated with the DbContext for some restrictive manipulations (for example, the data output limit)

@6bee 6bee closed this as completed Jul 10, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants