resueltos plan optimizar optimización optimizacion inner ejercicios ejemplos ejecución consultas c# sql entity-framework anonymous-types

c# - plan - Resultado de tipo anónimo del marco de la entidad de ejecución de consultas SQL



optimizar inner join sql server (5)

Estoy utilizando Entidad Framework 5.0 con el primer código de .NET Framework 4.0. Ahora sé que puedo ejecutar sql sin procesar en el marco de la entidad siguiendo

var students = Context.Database.SqlQuery<Student>("select * from student").ToList();

Está funcionando perfectamente, pero lo que quiero es devolver resultados anónimos. Por ejemplo, quiero solo columnas específicas de la tabla de estudiantes como las siguientes

var students = Context.Database.SqlQuery<Student>("select FirstName from student").ToList();

No está trabajando. da excepción

El lector de datos es incompatible con el ''MyApp.DataContext.Student'' especificado. Un miembro del tipo, ''StudentId'', no tiene una columna correspondiente en el lector de datos con el mismo nombre.

Así que he intentado tipo dynamic

var students = Context.Database.SqlQuery<dynamic>("select FirstName from student").ToList();

Tampoco está funcionando, devuelve un objeto vacío. No hay datos disponibles en ella.

¿Hay alguna forma de obtener un resultado de tipo anónimo a partir de una consulta SQL dinámica?


Aquí está la solución final que funcionó bien para mí.

public static System.Collections.IEnumerable DynamicSqlQuery(this Database database, string sql, params object[] parameters) { TypeBuilder builder = createTypeBuilder( "MyDynamicAssembly", "MyDynamicModule", "MyDynamicType"); using (System.Data.IDbCommand command = database.Connection.CreateCommand()) { try { database.Connection.Open(); command.CommandText = sql; command.CommandTimeout = command.Connection.ConnectionTimeout; foreach (var param in parameters) { command.Parameters.Add(param); } using (System.Data.IDataReader reader = command.ExecuteReader()) { var schema = reader.GetSchemaTable(); foreach (System.Data.DataRow row in schema.Rows) { string name = (string)row["ColumnName"]; //var a=row.ItemArray.Select(d=>d.) Type type = (Type)row["DataType"]; if(type!=typeof(string) && (bool)row.ItemArray[schema.Columns.IndexOf("AllowDbNull")]) { type = typeof(Nullable<>).MakeGenericType(type); } createAutoImplementedProperty(builder, name, type); } } } finally { database.Connection.Close(); command.Parameters.Clear(); } } Type resultType = builder.CreateType(); return database.SqlQuery(resultType, sql, parameters); } private static TypeBuilder createTypeBuilder( string assemblyName, string moduleName, string typeName) { TypeBuilder typeBuilder = AppDomain .CurrentDomain .DefineDynamicAssembly(new AssemblyName(assemblyName), AssemblyBuilderAccess.Run) .DefineDynamicModule(moduleName) .DefineType(typeName, TypeAttributes.Public); typeBuilder.DefineDefaultConstructor(MethodAttributes.Public); return typeBuilder; } private static void createAutoImplementedProperty( TypeBuilder builder, string propertyName, Type propertyType) { const string PrivateFieldPrefix = "m_"; const string GetterPrefix = "get_"; const string SetterPrefix = "set_"; // Generate the field. FieldBuilder fieldBuilder = builder.DefineField( string.Concat(PrivateFieldPrefix, propertyName), propertyType, FieldAttributes.Private); // Generate the property PropertyBuilder propertyBuilder = builder.DefineProperty( propertyName, System.Reflection.PropertyAttributes.HasDefault, propertyType, null); // Property getter and setter attributes. MethodAttributes propertyMethodAttributes = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig; // Define the getter method. MethodBuilder getterMethod = builder.DefineMethod( string.Concat(GetterPrefix, propertyName), propertyMethodAttributes, propertyType, Type.EmptyTypes); // Emit the IL code. // ldarg.0 // ldfld,_field // ret ILGenerator getterILCode = getterMethod.GetILGenerator(); getterILCode.Emit(OpCodes.Ldarg_0); getterILCode.Emit(OpCodes.Ldfld, fieldBuilder); getterILCode.Emit(OpCodes.Ret); // Define the setter method. MethodBuilder setterMethod = builder.DefineMethod( string.Concat(SetterPrefix, propertyName), propertyMethodAttributes, null, new Type[] { propertyType }); // Emit the IL code. // ldarg.0 // ldarg.1 // stfld,_field // ret ILGenerator setterILCode = setterMethod.GetILGenerator(); setterILCode.Emit(OpCodes.Ldarg_0); setterILCode.Emit(OpCodes.Ldarg_1); setterILCode.Emit(OpCodes.Stfld, fieldBuilder); setterILCode.Emit(OpCodes.Ret); propertyBuilder.SetGetMethod(getterMethod); propertyBuilder.SetSetMethod(setterMethod); }


Debe usar Sql en bruto para eso, el marco de la entidad SqlQuery<T> solo funcionará para objetos con tipos conocidos.

Aquí está el método que utilizo:

public static IEnumerable<dynamic> DynamicListFromSql(this DbContext db, string Sql, Dictionary<string, object> Params) { using (var cmd = db.Database.Connection.CreateCommand()) { cmd.CommandText = Sql; if (cmd.Connection.State != ConnectionState.Open) { cmd.Connection.Open(); } foreach (KeyValuePair<string, object> p in Params) { DbParameter dbParameter = cmd.CreateParameter(); dbParameter.ParameterName = p.Key; dbParameter.Value = p.Value; cmd.Parameters.Add(dbParameter); } using (var dataReader = cmd.ExecuteReader()) { while (dataReader.Read()) { var row = new ExpandoObject() as IDictionary<string, object>; for (var fieldCount = 0; fieldCount < dataReader.FieldCount; fieldCount++) { row.Add(dataReader.GetName(fieldCount), dataReader[fieldCount]); } yield return row; } } } }

Puedes llamarlo así:

List<dynamic> results = DynamicListFromSql(myDb,"select * from table where a=@a and b=@b", new Dictionary<string, object> { { "a", true }, { "b", false } }).ToList();


Lo uso asi

Clase de ORMC

public class ORMBase<T, TContext> : IORM<T> where T : class where TContext : DbContext, IDisposable, new()

Método:

public IList<TResult> GetSqlQuery<TResult>(string sql, params object[] sqlParams) { using (TContext con = new TContext()) { return Enumerable.ToList(con.Database.SqlQuery<TResult>(sql, sqlParams)); } }

Y finalmente usando

public class ResimORM : ORMBase<Resim, mdlOgrenciKulup>, IDisposable { public void Dispose() { GC.SuppressFinalize(this); } } ResimORM RE_ORM = new ResimORM(); List<Resim> a = RE_ORM.GetSqlQuery<Resim>(sql,null).ToList(); int b = RE_ORM.GetSqlQuery<int>(sql,null).FirstOrDefault();



Si tiene una entidad y solo desea recuperar algunas de las propiedades, puede obtener una solución aún mejor con la ayuda de la reflexión.

Este código se acumula en la misma muestra que en la respuesta anterior.

Además de esto, puede especificar un tipo y una matriz de campos que desea recuperar.

El resultado es de tipo IEnumerable.

public static class DatabaseExtension { public static IEnumerable<T> DynamicSqlQuery<T>(this Database database, string[] fields, string sql, params object[] parameters) where T : new() { var type = typeof (T); var builder = CreateTypeBuilder("MyDynamicAssembly", "MyDynamicModule", "MyDynamicType"); foreach (var field in fields) { var prop = type.GetProperty(field); var propertyType = prop.PropertyType; CreateAutoImplementedProperty(builder, field, propertyType); } var resultType = builder.CreateType(); var items = database.SqlQuery(resultType, sql, parameters); foreach (object item in items) { var obj = new T(); var itemType = item.GetType(); foreach (var prop in itemType.GetProperties(BindingFlags.Instance | BindingFlags.Public)) { var name = prop.Name; var value = prop.GetValue(item, null); type.GetProperty(name).SetValue(obj, value); } yield return obj; } } private static TypeBuilder CreateTypeBuilder(string assemblyName, string moduleName, string typeName) { TypeBuilder typeBuilder = AppDomain .CurrentDomain .DefineDynamicAssembly(new AssemblyName(assemblyName), AssemblyBuilderAccess.Run) .DefineDynamicModule(moduleName) .DefineType(typeName, TypeAttributes.Public); typeBuilder.DefineDefaultConstructor(MethodAttributes.Public); return typeBuilder; } private static void CreateAutoImplementedProperty(TypeBuilder builder, string propertyName, Type propertyType) { const string privateFieldPrefix = "m_"; const string getterPrefix = "get_"; const string setterPrefix = "set_"; // Generate the field. FieldBuilder fieldBuilder = builder.DefineField( string.Concat(privateFieldPrefix, propertyName), propertyType, FieldAttributes.Private); // Generate the property PropertyBuilder propertyBuilder = builder.DefineProperty( propertyName, PropertyAttributes.HasDefault, propertyType, null); // Property getter and setter attributes. MethodAttributes propertyMethodAttributes = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig; // Define the getter method. MethodBuilder getterMethod = builder.DefineMethod( string.Concat(getterPrefix, propertyName), propertyMethodAttributes, propertyType, Type.EmptyTypes); // Emit the IL code. // ldarg.0 // ldfld,_field // ret ILGenerator getterILCode = getterMethod.GetILGenerator(); getterILCode.Emit(OpCodes.Ldarg_0); getterILCode.Emit(OpCodes.Ldfld, fieldBuilder); getterILCode.Emit(OpCodes.Ret); // Define the setter method. MethodBuilder setterMethod = builder.DefineMethod( string.Concat(setterPrefix, propertyName), propertyMethodAttributes, null, new Type[] { propertyType }); // Emit the IL code. // ldarg.0 // ldarg.1 // stfld,_field // ret ILGenerator setterILCode = setterMethod.GetILGenerator(); setterILCode.Emit(OpCodes.Ldarg_0); setterILCode.Emit(OpCodes.Ldarg_1); setterILCode.Emit(OpCodes.Stfld, fieldBuilder); setterILCode.Emit(OpCodes.Ret); propertyBuilder.SetGetMethod(getterMethod); propertyBuilder.SetSetMethod(setterMethod); } }

Puedes llamarlo así:

var fields = new[]{ "Id", "FirstName", "LastName" }; var sql = string.Format("SELECT {0} FROM People WHERE Id = @id", string.Join(", ", fields)); var person = db.Database.DynamicSqlQuery<People>(fields, sql, new SqlParameter("id", id)) .FirstOrDefault();

En realidad, funciona solo en tipos simples y no hay manejo de errores.