Home > Enterprise >  Entity Framework C# queries from strings
Entity Framework C# queries from strings

Time:07-26

Is it possible to get elements in a sqlite table from a string with the name of the table (using Entity Framework)? How?

And how can I get only the value of a property? (I need to get a list of IDs to create a in html that's used to choose which element in a table the user wants to delete)

using using Microsoft.EntityFrameworkCore;

public static List<string> GetAllIdsFromTableName(string tableName)
    {
        var db = new dbContext();

        // What I would like to do: 
        // return db.tableName.Select(x => x.id).ToList<string>();
    }

CodePudding user response:

The following extension returns IQueryable<string> and you can materialise arrays, lists, or you can do it asynchronously:

var result = context.GetAllIdsFromTable("SomeTable", "Id")
    .ToList();

And implementation:

public static class QueryableExtensions
{
    private static readonly MethodInfo _toStringMethod = typeof(Convert).GetMethods()
        .Single(m =>
            m.Name == nameof(Convert.ToString) && m.GetParameters().Length == 1 &&
            m.GetParameters()[0].ParameterType == typeof(object)
        );

    public static IQueryable<string> GetAllIdsFromTable(this DbContext ctx, string tableName, string idColumnName = "Id")
    {
        var model = ctx.Model;

        var entityType = model.GetEntityTypes().FirstOrDefault(et =>
            tableName.Equals(et.GetTableName(), StringComparison.InvariantCultureIgnoreCase));

        if (entityType == null)
            throw new InvalidOperationException($"Entity for table '{tableName}' not found.");

        // GetColumnName() can be obsolete, it depends on EF Core version.
        var prop = entityType.GetProperties().FirstOrDefault(p =>
            idColumnName.Equals(p.GetColumnName(), StringComparison.InvariantCultureIgnoreCase));

        if (prop == null)
            throw new InvalidOperationException($"Property for column '{tableName}'.'{idColumnName}' not found.");

        var entityParam = Expression.Parameter(entityType.ClrType, "e");
        var ctxParam = Expression.Parameter(typeof(DbContext), "ctx");

        // ctx.Set<entityType>()
        var setQuery = Expression.Call(ctxParam, nameof(DbContext.Set), new[] { entityType.ClrType });

        Expression propExpression;
        if (prop.PropertyInfo == null)
            // 'prop' is Shadow property, so call via EF.Property(e, "name")
            propExpression = Expression.Call(typeof(EF), nameof(EF.Property), new[] { prop.ClrType },
                entityParam, Expression.Constant(prop.Name));
        else
            propExpression = Expression.MakeMemberAccess(entityParam, prop.PropertyInfo);

        propExpression = EnsureString(propExpression);

        // e => e.Prop
        var propLambda = Expression.Lambda(propExpression, entityParam);

        // ctx.Set<entityType>().Select(e => e.Prop)
        Expression selectAll = Expression.Call(typeof(Queryable), nameof(Queryable.Select),
            new[] { entityType.ClrType, typeof(string) },
            setQuery, Expression.Quote(propLambda));

        var constructQuery = Expression.Lambda<Func<DbContext, IQueryable<string>>>(selectAll, ctxParam);

        return constructQuery.Compile()(ctx);
    }

    private static Expression EnsureString(Expression expression)
    {
        if (expression.Type == typeof(string))
            return expression;

        if (expression.Type != typeof(object))
            expression = Expression.Convert(expression, typeof(object));

        expression = Expression.Call(_toStringMethod, expression);

        return expression;
    }
}
  • Related