Repository pattern (Demo DpRepos) - Invalid attempt to call Read when reader is closed

Repository pattern (Demo DpRepos) - Invalid attempt to call Read when reader is closed

Old forum URL: forums.lhotka.net/forums/t/11065.aspx


cconte posted on Tuesday, January 17, 2012

Hi All,

I'm currently working on de DpREPOS from the CSLA Core video series to learn how manipulate the DataAccess.

Actually, im focusing on the Repository pattern, using DataPortal_XYZ methods (EncapsulatedInvoke data reader)

So, I have reproduced a small demo where the structure is almost identical to the structure in the DpRepos example of the 3.8 demos.

but when i run my Demo I get the following error "Invalid attempt to call Read when reader is closed"  when the DataPortal_Fetch try to read the IDataReader provide by the DAL.

It's like if the  IdataReader  return by he DAL cannot keep data cause the connection reader or database is closed ?

Some of the things I’ve tried and checked
- The SQL request is correct and return data
- Added the option "MultipleActiveResultSets=True" to my connection string

see Below the code :

namespace DataAccess.MsSQL
{
    public class ProductEditDal : DataAccess.IProductEditDal
    {

        public IDataReader Fetch()
        {
            using (var ctx = ConnectionManager<SqlConnection>.GetManager("LioDB"))
            {
                using (var cm = ctx.Connection.CreateCommand())
                {
                    cm.CommandType = System.Data.CommandType.Text;
                    cm.CommandText = "SELECT ProductID, Name FROM Product";
                    return cm.ExecuteReader();
                }
            }
        }
...
}


namespace Library
{
    public partial class ProductEdit
    {

        #region Data

        private void DataPortal_Fetch(SingleCriteria<ProductEdit, int> criteria)
        {
            using (var dalFactory = DataAccess.DalFactory.GetManager())
            {
                var dal = dalFactory.GetProvider<DataAccess.IProductEditDal>();
                using (var dr = new SafeDataReader(dal.Fetch(criteria.Value)))
                {
                    // Here i get an Execption =>  Invalid attempt to call Read when reader is closed.  
                     dr.Read();
                    using (BypassPropertyChecks)
                    {
                        ProductID = dr.GetInt32("ProductID");
                        Name = dr.GetString("Name");
                    }
                }
            }

I appreciate any suggestions anyone can offer.

Thanks in advance for your help,

Cedric

JonnyBee replied on Tuesday, January 17, 2012

Hi,

You are NOT using the repository pattern if you return an IDataReader.

You should return an object with the values retrieved from the database and not an IDataReader.!!

           using (var ctx = ConnectionManager<SqlConnection>.GetManager("LioDB"))
            {
                using (var cm = ctx.Connection.CreateCommand())
                {
                    cm.CommandType = System.Data.CommandType.Text;
                    cm.CommandText = "SELECT ProductID, Name FROM Product";
                    return cm.ExecuteReader();
                }
            }

Using is translated in compiled code to

try
     -- execute statements
finally
    -- dispose object

so when you use using (var conn...... ) the connection will be closed when it leaves the scope. Hence your connection is closed before the method returns.

Your ProductEditDal should be created and the values (Id, Name) set inside the using block.
Fetch method should return an object of type ProductEditDal.

cconte replied on Tuesday, January 17, 2012

Hi JonnyBee,

My mistake, I'm using the EncapsulatedInvoke technique (DP_XYZ invoking DAL).

Actually, I have just found what i'm doing wrong , the DalManager was not well implement cause the Database connection was not persistent.

And like you said in the previous mail, my data reader was closed  before the method returns

Thx again for your help,

Cedric

sguolla replied on Wednesday, February 15, 2012

We're running into the exact same problem.  What exactly was the solution?  We have this code in our DAL:

 

 

 

 

 

 

using

 

 

(var ctx = ConnectionManager<SqlConnection>.GetManager("LocalDb"))

{

 

var cmd = ctx.Connection.CreateCommand();

cmd.CommandType =

 

CommandType.StoredProcedure;

cmd.CommandText =

 

"up_HarbingerPatientListOf";

cmd.Parameters.AddWithValue(

 

"@FacilityId", facilityId);

 

 

 

return cmd.ExecuteReader();}

Then we fail when we try to read from IDataReader (e.g. while (data.Read()) {} )

 

JonnyBee replied on Wednesday, February 15, 2012

hi,

Read the part in my previous answer on what using is translated to by the compiler.

If you need to return an open reader you should not use using on your data access. 

sguolla replied on Wednesday, February 15, 2012

Hi JonnyBee,

Thanks for the quick response.  We figured out our problem.  We were missing some code snippets in our DalManager class.  We zipped through things quickly yesterday without fully reading everything in our e-book.

Stewart G

Denver, CO

RockfordLhotka replied on Wednesday, February 15, 2012

> You are NOT using the repository pattern if you return an IDataReader.

That's not necessarily true. Your provider interface could be based on IDataReader - I do this in the Data Access book.

The thing with building a DAL interface based on IDataReader is that you have to fully understand how data readers and connections work, and live within those constraints.

Copyright (c) Marimer LLC