Risultato di tipo anonimo dal framework di quadro di esecuzione query SQL

Sto usando l’ quadro framework 5.0 con il primo approccio al codice di .net framework 4.0. Ora so che posso eseguire raw sql in entity framework seguendo

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

Funziona perfettamente ma quello che voglio è restituire risultati anonimi. Ad esempio voglio solo colonne specifiche dalla tabella degli studenti come segue

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

Non funziona. dà un’eccezione

Il lettore di dati non è compatibile con “MyApp.DataContext.Student” specificato. Un membro del tipo “StudentId” non ha una colonna corrispondente nel lettore di dati con lo stesso nome.

Quindi ho provato dynamic tipo dynamic

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

non funziona anche, restituisce un object vuoto. Nessun dato disponibile al suo interno.

C’è un modo per ottenere risultati di tipo anonimo da una query SQL dynamic?

Ecco la soluzione finale che ha funzionato bene per me.

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

È necessario utilizzare Sql raw per questo, il framework di SqlQuery funzionerà solo per gli oggetti con tipi noti.

ecco il metodo che uso:

 public static IEnumerable DynamicListFromSql(this DbContext db, string Sql, Dictionary Params) { using (var cmd = db.Database.Connection.CreateCommand()) { cmd.CommandText = Sql; if (cmd.Connection.State != ConnectionState.Open) { cmd.Connection.Open(); } foreach (KeyValuePair 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; for (var fieldCount = 0; fieldCount < dataReader.FieldCount; fieldCount++) { row.Add(dataReader.GetName(fieldCount), dataReader[fieldCount]); } yield return row; } } } } 

Puoi chiamarlo così:

 List results = DynamicListFromSql(myDb,"select * from table where [email protected] and [email protected]", new Dictionary { { "a", true }, { "b", false } }).ToList(); 

Puoi provare il codice da qui, scorrere verso il basso e trovare l’attrezzo di stankovski: http://www.codeproject.com/Articles/206416/Use-dynamic-type-in-Entity-Framework-SqlQuery

Dopo aver copiato il codice in una class statica, puoi chiamare questa funzione per ottenere ciò che desideri:

 var students = Context.Database.DynamicSqlQuery("select FirstName from student").ToList() 

Se hai un’ quadro e vuoi solo recuperare alcune delle proprietà, puoi ottenere una soluzione ancora migliore con l’aiuto della riflessione.

Questo codice si basa sullo stesso campione della risposta sopra.

Oltre a questo puoi specificare un tipo e una serie di campi che vuoi recuperare.

Il risultato è di tipo IEnumerable.

 public static class DatabaseExtension { public static IEnumerable DynamicSqlQuery(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); } } 

Puoi chiamarlo in questo modo:

 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(fields, sql, new SqlParameter("id", id)) .FirstOrDefault(); 

In realtà funziona solo su tipi semplici e non c’è gestione degli errori.