Sto tentando di creare un visualizzatore / editor di tabelle generico per un'applicazione MVC 6.
Attualmente uso
Context.GetEntityTypes();
Per restituirmi un elenco di tabelle.
Ora ho bisogno di recuperare i dati per un tipo specifico. La mia attuale implementazione è:
// On my context
public IQueryable<dynamic> GetDbSetByType(string fullname)
{
Type targetType = Type.GetType(fullname);
var model = GetType()
.GetRuntimeProperties()
.Where(o =>
o.PropertyType.IsGenericType &&
o.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>) &&
o.PropertyType.GenericTypeArguments.Contains(targetType))
.FirstOrDefault();
if (null != model)
{
return (IQueryable<dynamic>)model.GetValue(this);
}
return null;
}
Con questo codice nel mio controller
[HttpGet("{requestedContext}/{requestedTable}/data")]
public IActionResult GetTableData(string requestedContext, string requestedTable)
{
var data = Request.Query;
var context = GetContext(requestedContext);
if (context == null)
{
return new ErrorObjectResult("Invalid context specified");
}
var entity = context.GetEntity(requestedTable);
if (entity == null)
{
return new ErrorObjectResult("Invalid table specified");
}
var set = context.GetDbSetByType(entity.ClrType.AssemblyQualifiedName);
if (set == null)
{
return new ErrorObjectResult("Invalid table specified - DbSet could not be found");
}
var start = Convert.ToInt32(data["start"].ToString());
var count = Convert.ToInt32(data["length"].ToString());
var search = data["search[value]"];
return new ObjectResult(set.Skip(start).Take(count));
}
Così com'è, questo restituirà i dati del count
della lunghezza e start
posizione. Tuttavia, non posso eseguire query sulle proprietà specifiche di IQueryable<dynamic>
.
Il problema è:
object set
su un DbSet<T>
modo da poter eseguire le mie query? Se ho impostato un punto di interruzione e ispezionato, posso vedere tutti i miei dati seduti lì. NOTA: Questo è EF7
INFORMAZIONI ADDIZIONALI:
<mysystem>.Models.Shared.Users
requestedTable
è il tipo EG completo: <mysystem>.Models.Shared.Users
EDIT (2016/5/5)
Ho finito per fare tutto in un semplice SQL - se qualcuno riesce a farlo funzionare per favore fammi sapere!
Ciò sarebbe più semplice utilizzando un metodo generico e utilizzando DbContext.Set<TEntity>()
. È possibile creare un metodo generico in fase di esecuzione come questo:
public IActionResult GetTableData(string requestedContext, string requestedTable)
{
var context = GetContext(requestedContext);
if (context == null)
{
return new ErrorObjectResult("Invalid context specified");
}
var entity = context.GetEntity(requestedTable);
if (entity == null)
{
return new ErrorObjectResult("Invalid table specified");
}
var boundMethod = s_getTableDataMethodInfo.MakeGenericMethod(entity.ClrType);
return boundMethod.Invoke(this, new object[] { context }) as IActionResult;
}
private static readonly MethodInfo s_getTableDataMethodInfo
= typeof(MyController).GetTypeInfo().GetDeclaredMethod("GetTableDataForEntity");
private IActionResult GetTableDataForEntity<TEntity>(DbContext context)
where TEntity : class
{
var data = Request.Query;
var start = Convert.ToInt32(data["start"].ToString());
var count = Convert.ToInt32(data["length"].ToString());
var search = data["search[value]"];
return new ObjectResult(context.Set<TEntity>().Skip(start).Take(count));
}