views:

83

answers:

2

I am trying to return an XMLReader from a data access class that calls a stored proc to run a FOR XML query. The problem is, I can't call close() on the sql connection when I return the xmlreader or the reading will terminate. The class that calls for the xmlreader doesn't know anything about a sql connection so it can't be in charge of closing the connection. How can I handle this?

+2  A: 

You could to build a XmlDocument and to return it, so you can have that database connection closed.

Rubens Farias
The problem is, this xml could be up to 200mb, that's why I was trying the reader approach. Do I really want to hold a 200mb xmldocument in memory?
Bob
In this case, you'll need to keep that connection open, or to make your data access layer disposable, so you can call it with `using`
Rubens Farias
+1  A: 

Use an anonymous method to wrap the call.

For example, assuming you have a datalayer class, add a similar method to the data layer:

public delegate void DoSomethingInvoker();
class DataLayer
{
   //myReader needs to be declared externally in other to access it from the doSomething delegate
   public void MethodThatGetsAsXmlReader(XmlReader myReader, DoSomethingInvoker doSomething)
   {
      myReader = GetXmlReaderFromDB();
      doSomething();
      CloseDbConnection();      //close connections, do cleanup, and any other book keeping can be done after the doSomething() call
   }
}

To call/use it, you simply do this in your high level class

DataLayer dl = new DataLayer();
XmlReader myReader = null;  //variables declared outside the scope of the anonymous method are still accessible inside it through the magic of closures
dl.MethodThatGetsAsXmlReader(myReader, delegate()
   {
      //do all work that involves myReader here
      myReader.read();   
      Console.out.println(myReader.value);
   });
//at this point myReader is closed and cannot be used

Basically, you pass the code you want to execute to the datalayer, the data layer fetches the xmlreader, calls your code against it, and then does cleanup.

I use a similar technique for wrapping transaction logic in my code

DataLayer dl = new DataLayer();
dl.Transaction(delegate()
   {
        dl.DbCall1();
        dl.DbCall2();
        dl.DbCall3();
    });

It makes the code nice and readable, while still keeping it organized and layered;

Zack
cool! thanks you.
Bob