Return Anonymous Type using SqlQuery RAW Query in Entity Framework

后端 未结 2 837
长情又很酷
长情又很酷 2020-12-11 05:10

How can I make Entity Framework SqlQuery to return an Anonymous type.

Right now I run a context.TheObject.SqlQuery() RAW query. the query joins two tabl

相关标签:
2条回答
  • 2020-12-11 05:31

    Here's what I did.

    1. Execute sp and get the results into a data reader
    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. Read individual values from each row into a expando object and put the list of expando objects into an array
                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. Get the list of columns by using the reader.GetSchemaTable() method
               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());
                    }
    

    Usage

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

    In my case, I happened to use SPs but this should work with queries. All you have to do is replace the command with the following ( and remove all the parameter passing)

    command.CommandType = CommandType.Text;
    command.CommandText = "select * from SomeTable";
    
    0 讨论(0)
  • 2020-12-11 05:54

    I'm going out on a limb here, and will try to address your underlying problem instead of directly answering your question.

    Your scenario with the pre-defined class should work. A likely pitfall is that the column names and the properties of your class did not match up.

    Sample code (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; }
    

    I'd strongly advise you to revisit your problematic code using explicit types.


    In direct response to your question: no, you can't return anonymous types from SqlQuery. The best you can do is build dynamic objects, but that unfortunately requires a fair bit of manual work using TypeBuilder. See http://www.codeproject.com/Articles/206416/Use-dynamic-type-in-Entity-Framework-SqlQuery for a sample.

    0 讨论(0)
提交回复
热议问题