views:

69

answers:

4

Or what's the recommended way to read and write at the same time? Having two connections open is the only way? This is on a plain Windows Forms C# (.NET 3.5) app

using (SqlConnection conn = new SqlConnection(connStr)) {
    SqlCommand cmdRead = new SqlCommand("select stools from foo", conn);
    SqlDataReader rdr = cmdRead.ExecuteReader();
    SqlCommand cmdWrite = new SqlCommand("insert into bar values (@beer)", conn);
    SqlParameter beer = new SqlParameter("@beer", SqlDbType.Int);
    cmdWrite.Parameters.Add(beer);
    while(rdr.Read()) {
        int stools = rdr.GetInt32(0);
        cmdWrite.Parameters["@beer"].value = stools;
        //Next line fails for an open data reader associated to the "command"
        cmdWrite.ExecuteNonQuery(); 
    }
    rdr.Close()
}

This, OTOH, works, but looks ugly to me (besides of opening an extra connection)

using (SqlConnection connR = new SqlConnection(connStr)) {
    using (SqlConnection connW = new SqlConnection(connStr)) {
        SqlCommand cmdRead = new SqlCommand("select stools from foo", connR);
        SqlDataReader rdr = cmdRead.ExecuteReader();
        SqlCommand cmdWrite = new 
                         SqlCommand("insert into bar values (@beer)", connW);
        SqlParameter beer = new SqlParameter("@beer", SqlDbType.Int);
        cmdWrite.Parameters.Add(beer);
        while(rdr.Read()) {
            int stools = rdr.GetInt32(0);
            cmdWrite.Parameters["@beer"].value = stools;
            cmdWrite.ExecuteNonQuery(); 
        }
        rdr.Close()
    }
}

In this simple case, read all the stools, store them in a list, close the reader and then write them will work (as long as there aren't many stools in the database), but in more complex cases it starts being unwieldy and memory hungry, so that's also not desirable.

+2  A: 

Why not having two methods: one for reading and one for writing, each using its own connection drawn from the connection pool.

Reading

using (SqlConnection conn = new SqlConnection(connStr))
using (SqlCommand cmdRead = new SqlCommand("select stools from foo", conn))
{
    conn.Open();  
    using (SqlDataReader rdr = cmdRead.ExecuteReader())
    {
        while(rdr.Read()) 
        {
            int stools = rdr.GetInt32(0);
        }
    }
}

Writing

using (SqlConnection conn = new SqlConnection(connStr))
using (SqlCommand cmdWrite = new SqlCommand("insert into bar values (@beer)", conn))
{
    conn.Open();
    SqlParameter beer = new SqlParameter("@beer", SqlDbType.Int);
    cmdWrite.Parameters.Add(beer);
    cmdWrite.Parameters["@beer"].value = stools;
    cmdWrite.ExecuteNonQuery(); 
}

And then just call them on different threads. This makes methods clearer and more specific.

Darin Dimitrov
But make them hungrier, as you'd have to have a datastructure to hold what's been read and pass that to the write thread. This is what I mentioned in the last paragraph of the question
Vinko Vrsalovic
one int stool fits in memory fine, but a large result set will have to be cached. A row by row processing is much more efficient and that's what MARS was designed to address.
Remus Rusanu
+1  A: 

You can't write while the DataReader is open, creating a second connection is needed in this situation, and IMHO it's not a design issue.

Pedro
+1  A: 

Well the obvious question is why are you doing this in code at all?

You're selecting from one table to write into another - that screams insert query to me.

Doubtless the real world example is more complex in which case you need two connections because datareaders work by holding the connection open 'til you're done and that's more or less that.

Murph
Yes, I wanted confirmation that there's no way out of two connections or a datastructure holding the resultset. And of course the real world example is more complex.
Vinko Vrsalovic
Whilst the real world being more complex is a fair assumption from your reputation *making* assumptions is a bad habit for a programmer (-: Its worth noting that one of the options for a data reader is to automagically close the reader when it runs out of data, the existence of the option implies the constraint that you're working under with data readers - and allows you to enscapsulate creation of a data reader in a method (though it took me an age to work that out trying to populate drop downs in asp.net, erm, 6 years ago...)
Murph
+3  A: 

With SQL 2005 and later, you can use Multiple Active Result Sets (MARS):

http://msdn.microsoft.com/en-us/library/ms345109%28SQL.90%29.aspx

http://msdn.microsoft.com/en-us/library/ms131686.aspx

For this to work, you need to enable it in your connection string.

RickNZ
So there is a way. Thanks!
Vinko Vrsalovic
"Learn something new everyday [x]"
Murph