来自sql查询执行entity framework的匿名类型结果

我使用entity framework5.0与.net框架4.0代码的第一种方法。 现在我知道我可以通过以下方式在entity framework中运行原始sql

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

它工作得很好,但我想要的是返回匿名结果。 例如,我只想要学生表中的特定列,如下所示

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

它不起作用。 它给了例外

数据读取器与指定的“MyApp.DataContext.Student”不兼容。 类型为“StudentId”的成员在数据读取器中没有具有相同名称的相应列。

所以我尝试过dynamic类型

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

它也没有用,它返回一个空对象。 没有可用的数据。

有没有办法从动态SQL查询中获取匿名类型结果?

这是最终解决方案,对我来说很好。

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

您必须使用原始Sql,权限框架SqlQuery仅适用于具有已知类型的对象。

这是我使用的方法:

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

你可以这样称呼它:

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

您可以从这里尝试代码,向下滚动并找到stankovski的工具: http : //www.codeproject.com/Articles/206416/Use-dynamic-type-in​​-Entity-Framework-SqlQuery

将代码复制到静态类后,可以调用此函数来获得所需内容:

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

如果你有一个实体并且你只想要一些属性,你可以在reflection的帮助下获得更好的解决方案。

此代码建立在与上面答案相同的示例中。

除此之外,您还可以指定要返回的类型和字段数组。

结果是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); } } 

你可以这样称呼它:

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

实际上它只适用于简单类型,并且没有error handling。