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;
}
}