【问题标题】:Return Anonymous Type using SqlQuery RAW Query in Entity Framework在实体框架中使用 SqlQuery RAW 查询返回匿名类型
【发布时间】:2015-04-24 16:37:01
【问题描述】:

如何使实体框架 SqlQuery 返回匿名类型。

现在我运行context.TheObject.SqlQuery() RAW 查询。该查询连接两个表,我想返回连接表的结果。

如果我将它与 context.TheObject.SqlQuery() 类型一起使用,我只能看到相同类型的表的结果。

我试过db.Database.SqlQuery<DbResults>("the sql query here");使用与结果对象匹配的预定义类,但所有字段均为空。

在 MySQL 中使用 Entity Framework 6。

【问题讨论】:

    标签: c# mysql sql .net entity-framework


    【解决方案1】:

    我在这里很冒险,会尝试解决您的根本问题,而不是直接回答您的问题。

    您使用预定义类的场景应该可以工作。一个可能的陷阱是您的类的列名和属性不匹配。

    示例代码(LinqPad)

        var results = Database.SqlQuery<TestResult>("select r.Name, b.BankName from relation r inner join BankAccount b on b.RelationId = r.Id where r.Id = 2");
        results.Dump();
    }
    
    public class TestResult {
        public string Name { get; set; }
        public string BankName { get; set; }
    

    我强烈建议您使用显式类型重新访问有问题的代码。


    直接回答您的问题:不,您不能从 SqlQuery 返回匿名类型。您可以做的最好的事情是构建动态对象,但不幸的是,这需要使用 TypeBuilder 进行大量手动工作。有关示例,请参阅 http://www.codeproject.com/Articles/206416/Use-dynamic-type-in-Entity-Framework-SqlQuery

    【讨论】:

    • 重要的是要注意属性必须有getter和setter。这不起作用:public class TestResult { public string Name; public string BankName; }.
    • 从技术上讲,这些是字段,而不是属性......但是,这是一个常见的陷阱,可能需要指出。
    【解决方案2】:

    这就是我所做的。

    1. 执行 sp 并将结果输入数据读取器
    public static async Task<IEnumerable<object>> GetAnonymousResults(IUnitOfWork unitOfWork, string spName, SqlParameter[] outParameters, params SqlParameter[] parameters)
            {
    
                //meh, you only need the context here. I happened to use UnitOfWork pattern and hence this.
                var context = unitOfWork as DbContext;
    
                DbCommand command = new SqlCommand();
                command.CommandType = CommandType.StoredProcedure;
                command.CommandText = spName;
                command.Connection = context.Database.Connection;
    
                command.Parameters.AddRange(parameters);
    
                //Forget this if you don't have any out parameters
                command.Parameters.AddRange(outParameters);
    
                try
                {
                    command.Connection.Open();
                    var reader = await command.ExecuteReaderAsync();
                    return reader.ToObjectList();//A custom method implemented below
                }
                finally
                {
                    command.Connection.Close();
                }
            }
    
    1. 将每一行的单个值读入一个expando对象,并将expando对象的列表放入一个数组中
                public static List<object> ToObjectList(this IDataReader dataReader, bool ignoreUnmappedColumns = true)
                {
                    var list = new List<object>();
                    while (dataReader.Read())
                    {
                        IEnumerable<string> columnsName = dataReader.GetColumnNames();//A custom method implemented below 
                        var obj = new ExpandoObject() as IDictionary<string, object>;
    
                        foreach (var columnName in columnsName)
                        {
                            obj.Add(columnName, dataReader[columnName]);
                        }
                        var expando = (ExpandoObject)obj;
    
                        list.Add(expando);
                    }
    
                    return list;
                }
    
    1. 使用 reader.GetSchemaTable() 方法获取列列表
               public static IEnumerable<string> GetColumnNames(this IDataReader reader)
                    {
                        var schemaTable = reader.GetSchemaTable();
                        return schemaTable == null
                            ? Enumerable.Empty<string>()
                            : schemaTable.Rows.OfType<DataRow>().Select(row => row["ColumnName"].ToString());
                    }
    

    用法

     var results =
                      await
                          StandaloneFunctions.GetAnonymousResults(_unitOfWork, "spFind",
                              outputParameters,parameters);
    

    就我而言,我碰巧使用了 SP,但这应该适用于查询。您所要做的就是将命令替换为以下内容(并删除所有传递的参数)

    command.CommandType = CommandType.Text;
    command.CommandText = "select * from SomeTable";
    

    【讨论】:

    • 太棒了!像魅力一样工作。谢谢。
    • 但是,但是,但是……这不是 EF。
    • 很好的解决方法!!我认为使用普通的 EF,我们无法在不创建类的情况下实现直接的 SQL。在我的情况下,我有动态查询,我无法预料查询将映射到哪个类,所以这是一个很好的解决方案。谢谢你节省了我的时间。我对返回类型做了一些改动,而不是返回 List 我们可以返回 List> 我的字典值有 CSV 字符串,需要转换成列表。
    猜你喜欢
    • 2018-01-11
    • 2011-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-18
    • 2015-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多