Contexto de la base de datos y retorno del conjunto dynamic de resultados en ASP.NET MVC

En MVC 4 y EF 5 quiero ejecutar una consulta dinámica.

var returndata = Context.Database.SqlQuery(Type, strsql, null); 

No sé cuántos campos volverá y nombre. De este resultado quiero hacer una estructura de tabla que se mostrará en la vista.

Pregunta: ¿Qué debo pasar como tipo?

mi consulta vuelve debajo del resultado:

Campo 1, Campo 2, Campo 3, Campo 4, Campo 5

Fila1 …

Fila2 ..

Agradecemos cualquier sugerencia.

Podría usar una consulta de SQL sin formato porque EF no admite eso:

 private static IEnumerable Read(DbDataReader reader) { while (reader.Read()) { var values = new List(); for (int i = 0; i < reader.FieldCount; i++) { values.Add(reader.GetValue(i)); } yield return values.ToArray(); } } 

y entonces:

 public ActionResult Index() { using (var ctx = new UsersContext()) using (var cmd = ctx.Database.Connection.CreateCommand()) { ctx.Database.Connection.Open(); cmd.CommandText = "SELECT * FROM UserProfile"; using (var reader = cmd.ExecuteReader()) { var model = Read(reader).ToList(); return View(model); } } } 

y finalmente en su opinión:

 @model IEnumerable  @foreach (var row in Model) {  @foreach (var column in row) {  }  } 
@column

Este método carga datos de la selección de SQL (con parámetros) a la lista de filas, donde cada fila es el diccionario de columnas (la clave es el nombre de la columna).

 private static List> LoadData(string sqlSelect, params object[] sqlParameters) { var table = new List>(); using (var ctx = new DbEntities()) { ctx.Database.Connection.Open(); using (var cmd = ctx.Database.Connection.CreateCommand()) { cmd.CommandText = sqlSelect; foreach (var param in sqlParameters) cmd.Parameters.Add(param); using (var reader = cmd.ExecuteReader()) { while (reader.Read()) { var row = new Dictionary(); for (int i = 0; i < reader.FieldCount; i++) row[reader.GetName(i)] = reader[i]; table.Add(row); } } } } return table; } 

Finalmente, hice que utilizaba la opción TypeBuilder sugerida por “Mortalus” y el objeto ExpandoObject. Tiene poca sobrecarga de rendimiento en este momento.

Tome el código de Typebuilder de la respuesta de “Mortalus” y luego hice un código de acuerdo con mi requerimiento como se muestra a continuación.

 List> expandolist = new List>(); foreach (var item in returndata) { IDictionary expando = new ExpandoObject(); foreach (PropertyDescriptor propertyDescriptor in TypeDescriptor.GetProperties(item)) { var obj = propertyDescriptor.GetValue(item); expando.Add(propertyDescriptor.Name, obj); } expandolist.Add(new Dictionary(expando)); } return expandolist; 

así que ahora, tengo el objeto “Diccionario” del objeto dynamic. y al usarlo, puede trabajar fácilmente en tiempo de diseño en lugar de esperar hasta el tiempo de ejecución utilizando el objeto “dynamic”.

Sin saber nada sobre el tipo que se devuelve, creo que podría estar fuera de suerte.

Si sabe en qué patrones podría caer, podría usar algunos try { } catch () { } en interfaces que coincidan con esos parámetros en su consulta dinámica, pero parece que podría ser un poco doloroso.

Desafortunadamente, EF no materializará objetos a menos que conozca su Type .

Si esto es realmente necesario para usted, creo que lo mejor sería recurrir a ADO.NET y DataTable .

Publicación similar por Darin Dimitrov, pero devuelve DataTable

 public DataTable QueryToTable(Entities db, string queryText, SqlParameter[] parametes) { using ( DbDataAdapter adapter = new SqlDataAdapter()) { adapter.SelectCommand = db.Database.Connection.CreateCommand(); adapter.SelectCommand.CommandText = queryText; if (parametes != null) adapter.SelectCommand.Parameters.AddRange(parametes); DataTable table = new DataTable(); adapter.Fill(table); return table; } } 

Utilizar

 SqlParameter[] parametes = new[] { new SqlParameter("date_from", dateFrom) }; DataTable tab = QueryToTable(new Entities(), "Select * From SomeTable Where ADate >= @date_from", parametes); 

Ejemplo para MS SQL Server

Recientemente me he topado con este ejemplo:

http://www.markzhou.com/blog/post/2011/06/02/Use-dynamic-type-in-Entity-Framework-41-SqlQuery()-method.aspx

No he tenido tiempo de probarlo yo mismo, pero parece que es posible con un trabajo adicional para construir el tipo dynamic.

En resumen, querrías hacer algo como esto:

  TypeBuilder builder = Program.CreateTypeBuilder( "MyDynamicAssembly", "MyModule", "MyType"); Program.CreateAutoImplementedProperty(builder, "name", typeof(string)); Program.CreateAutoImplementedProperty(builder, "type", typeof(string)); Program.CreateAutoImplementedProperty(builder, "id", typeof(int)); Type resultType = builder.CreateType(); dynamic queryResult = context.Database.SqlQuery( resultType, "SELECT * FROM sys.sysobjects"); 

Donde TypeBuilder se describe en detalle en la publicación que he adjuntado.

Agregando a la respuesta de Petr Voborník, consulta dinámica, agrego inserción dinámica de ResultSet, mi aplicación toma la consulta dinámica de todas las tablas de toda la base de datos, una porción a la vez y luego inserta los resultados dynamics en una base de datos remota, usando siempre cifrado ( omitido aquí). Pasando un comando sb y un objeto de parámetro.

  public void StoreData(DbContext dbContext, Dictionary columnInfo, List> multiInsertObj, string tableName) { _ctx = dbContext; _columnInfo = columnInfo; var sb = new StringBuilder(); sb.Append(BuildSqlCommand(tableName, columnInfo, multiInsertObj.Count)); ExecuteSqlCommand(sb, GetParamsObject(columnInfo, multiInsertObj)); } private static StringBuilder BuildSqlCommand(string tableName, Dictionary variableInfo, int variableCount) { //Build sql command var sb = new StringBuilder(); sb.Append("INSERT INTO dbo." + tableName + "("); foreach (var variable in variableInfo) { sb.Append(variable.Key); sb.Append(", "); } sb.Append("SystemNumber, "); sb.Remove(sb.Length - 2, 2).Append(") VALUES "); for (var i = 0; i < variableCount; i++) { sb.Append("("); foreach (var name in variableInfo.Keys) { sb.Append("@" + name + "_" + i + ","); } sb.Append("@SystemNumber" + "_" + i + ","); sb.Remove(sb.Length - 1, 1).Append("),"); } sb.Remove(sb.Length - 1, 1); return sb; } private static object[] GetParamsObject(Dictionary columnInfo, List> multiInsertObj) { var variableCount = multiInsertObj.Count; var rowCount = multiInsertObj[0].Keys.Count; var objectLength = (rowCount + 1) * variableCount; var variableDataTypes = columnInfo.Values.ToList(); var paramObj = new object[objectLength]; var j = 0; var i = 0; foreach (var row in multiInsertObj) { var k = 0; foreach (var data in row) { var sb = new StringBuilder(); sb.Append("@"); sb.Append(data.Key); sb.Append("_" + i); paramObj[j] = new SqlParameter(sb.ToString(), SetSqlDataType(variableDataTypes[k])) { Direction = Input, Value = data.Value }; j++; k++; } paramObj[j] = new SqlParameter(("@SystemNumber" + "_" + i), SetSqlDataType("int")) { Direction = Input, Value = _systemNumber }; i++; j++; } return paramObj; } private static void ExecuteSqlCommand(StringBuilder sb, params object[] sqlParameters) { using (_ctx) { _ctx.Database.Connection.Open(); using (var cmd = _ctx.Database.Connection.CreateCommand()) { cmd.CommandText = sb.ToString(); foreach (var param in sqlParameters) cmd.Parameters.Add(param); try { cmd.ExecuteNonQuery(); } catch (Exception e) { Console.WriteLine(e); throw; } } } }