Search code examples
c#asp.net.netsql-serverasp.net-mvc

Select from multiple tables in one call


In my code I have a page that includes information from 3 different tables. To show this information I make 3 SQL select calls and unite them in one list to pass as Model to my view. Can I do it with one SQL call? Data has no connection with one another.

My code:

public ActionResult Index()
{
    StorePageData PageData = new StorePageData();
    return View(PageData);
}
public class StorePageData
{
     public List<Table1Data> Table1 { get; set; }
     public List<Table2Data> Table2 { get; set; }
     public List<Table3Data> Table3 { get; set; }

     public StorePageData()
     {
          Table1  = //loading from Database1
          Table2  = //loading from Database2
          Table3  = //loading from Database3
     }
}
public class Table1Data
{
     public int Id { get; set; }
     public double Info1 { get; set; }
     public string Info2 { get; set; }
}
public class Table2Data
{
     public int Id { get; set; }
     public List<int> Info1 { get; set; }
     public List<int> Info2 { get; set; }
}
public class Table3Data
{
     public int Id { get; set; }
     public List<string> Info1 { get; set; }
     public List<string> Info2 { get; set; }
}

If there is a way to load all 3 tables in one SQL request it will improve significantly the load time of this page.

Thank you.


Solution

  • You can get multiple result sets in a single request using a DataReader. You can use it with or without entity framework.

    If you are using Entity Framework, you can pass a DbDataReader to ObjectContext.Translate method to translate multiple result set to requested object types. The command which is used to create the data reader can be a stored procedure, or you can simply use a command containing your queries to shape multiple result set.

    Example

    List<Table1> list1;
    List<Table2> list2;
    
    using (var cn = new SqlConnection(@"Connection String"))
    {
        cn.Open();
        using (var cmd = cn.CreateCommand())
        {
            cmd.CommandText = "SELECT * FROM Table1; SELECT * FROM Table2";
            var reader = cmd.ExecuteReader(); 
            using (var db = new YourDbContext())
            {
                var context = ((IObjectContextAdapter)db).ObjectContext;
                list1 = context.Translate<Table1>(reader).ToList();
                reader.NextResult();
                list2 = context.Translate<Table2>(reader).ToList();
            }
        }
    }
    

    If you are using SqlDataAdapter, you can simply pass a command containing your queries and then using Fill, fill a data set. The data adapter itself will use DataReader behind the scene.

    Example

    var connectionString = @"Connection String";
    var commandText = "SELECT * FROM Table1; SELECT * FROM Table2;";
    var ds = new DataSet();
    using (var da = new SqlDataAdapter(commandText, connectionString))
    {
        da.Fill(ds);
    }
    

    Then you can shape the results to List<Table1> and List<Table2>.