InvalidOperationException: open DataReader ...

Hi,

I create an object, bind it to some controls, a user clicks 'Save' and the object gets added to the DLinq DataContext. A call to SubmitChanges() throws the exception. Is this a known issue Or am I just doing something wrong

Thanks,

Rana

--

System.InvalidOperationException was caught
Message="There is already an open DataReader associated with this Command which must be closed first."
Source="System.Data"
StackTrace:
at System.Data.SqlClient.SqlInternalConnectionTds.ValidateConnectionForExecute(SqlCommand command)
at System.Data.SqlClient.SqlInternalConnection.BeginSqlTransaction(IsolationLevel iso, String transactionName)
at System.Data.SqlClient.SqlConnection.BeginTransaction(IsolationLevel iso, String transactionName)
at System.Data.SqlClient.SqlConnection.BeginTransaction(IsolationLevel iso)
at System.Data.DLinq.SqlClient.SqlConnectionManager.LocalTxShim.System.Transactions.IPromotableSinglePhaseNotification.Initialize() in c:\PdcBuild\query\DLinq\Engine\SqlConnectionManager.cs:line 162
at System.Transactions.TransactionStatePSPEOperation.PSPEInitialize(InternalTransaction tx, IPromotableSinglePhaseNotification promotableSinglePhaseNotification)
at System.Transactions.TransactionStateActive.EnlistPromotableSinglePhase(InternalTransaction tx, IPromotableSinglePhaseNotification promotableSinglePhaseNotification, Transaction atomicTransaction)
at System.Transactions.Transaction.EnlistPromotableSinglePhase(IPromotableSinglePhaseNotification promotableSinglePhaseNotification)
at System.Data.DLinq.SqlClient.SqlConnectionManager.LocalTxShim.TryEnlistSinglePhase() in c:\PdcBuild\query\DLinq\Engine\SqlConnectionManager.cs:line 151
at System.Data.DLinq.SqlClient.SqlConnectionManager.Enlist() in c:\PdcBuild\query\DLinq\Engine\SqlConnectionManager.cs:line 125
at System.Data.DLinq.SqlClient.SqlConnectionManager.UseConnection(ISqlConnectionUser user) in c:\PdcBuild\query\DLinq\Engine\SqlConnectionManager.cs:line 86
at System.Data.DLinq.SqlClient.SqlContext.get_IsServer2KOrEarlier() in c:\PdcBuild\query\DLinq\Engine\SqlContext.cs:line 338
at System.Data.DLinq.SqlClient.SqlContext.Execute(Expression query) in c:\PdcBuild\query\DLinq\Engine\SqlContext.cs:line 242
at System.Data.DLinq.Model.SimpleChangeDirector.ExecuteInsertWithFacts(Statement cmd, Object item, StringBuilder changeText) in c:\PdcBuild\query\DLinq\Model\ChangeDirector.cs:line 233
at System.Data.DLinq.Model.SimpleChangeDirector.ExecuteInsert(Object item, StringBuilder changeText) in c:\PdcBuild\query\DLinq\Model\ChangeDirector.cs:line 201
at System.Data.DLinq.Model.SimpleChangeDirector.Insert(Object item) in c:\PdcBuild\query\DLinq\Model\ChangeDirector.cs:line 53
at System.Data.DLinq.Model.ChangeProcessor.SubmitChanges() in c:\PdcBuild\query\DLinq\Model\ChangeProcessor.cs:line 41
at System.Data.DLinq.DataContext.SubmitChanges() in c:\PdcBuild\query\DLinq\DataContext.cs:line 219
at Trtiya.Controls.DLinq.EntityPanel.m_btnSave_Click(Object sender, RoutedEventArgs e) in C:\Projects\ThousandSunsRising\Trtiya.Controls\DLinq\EntityPanel.cs:line 393



Answer this question

InvalidOperationException: open DataReader ...

  • Nikolaus Brennig

    Miha,

    Indeed, why not show you some code.

    The offending line of code is in assigning a reflected Table<T> to a ListBox.ItemsSource. The assignment is made prior to displaying a Page. Removing the Table<T> assignment removes the exceptional behavior seen during the 'Save' button click handler.

    ...

    // used when setting up gui controls

    Type[] types = { enumerationType };

    Type targetType = typeof(Table<>).MakeGenericType(types);

    // get the table containing the enumeration entityType in model

    FieldInfo[] fields = this.Model.GetType().GetFields();

    foreach (FieldInfo fiCandidate in fields)

    {

    if (fiCandidate.FieldType == targetType)

    {

    object oEnumerable = fiCandidate.GetValue(this.Model);

    // When the next line is commented the exception disappears

    //listBox.ItemsSource = (IEnumerable)oEnumerable;

    listBox.ItemTemplate = listBoxDataTemplate;

    break;

    }

    }

    ...

    // The event handler

    void m_btnSave_Click(object sender, RoutedEventArgs e)

    {

    try

    {

    // added new entity to DLinq DataContext

    if (m_bIsNewEntity)

    {

    Type[] types = { m_Type };

    Type targetType = typeof(Table<>).MakeGenericType(types);

    // get the table field

    FieldInfo[] fields = this.Model.GetType().GetFields();

    foreach (FieldInfo fiCandidate in fields)

    {

    if (fiCandidate.FieldType == targetType)

    {

    object oGenericTable = fiCandidate.GetValue(this.Model);

    MethodInfo miAdd = targetType.GetMethod("Add");

    object[] oEntityParameter = new object[] { this.Entity };

    // add the entity to the DataContext Table

    miAdd.Invoke(oGenericTable, oEntityParameter);

    break;

    }

    }

    }

    // save changes

    this.Model.SubmitChanges();

    // Raise EntitySaved event

    this.OnEntitySaved(m_oEntity);

    }

    catch (Exception ex)

    {

    this.Model.RejectChanges();

    }

    }

    Is listBox.ItemsSource simply being assigned improperly

    Cheers,

    Rana


  • Chrisww2

    Thank You
  • Tom ODonnell

    There aren't any open DataReaders, DataSets, instances of DataReaders or instances of DataSets. Only DLinq is used.

    The database table which is queried for the ListBox.ItemsSource does not have any data in it. Possibly DLinq maintains an open reader until some data is returned


  • JohnEwing

    Do you have another open database reader elsewhere in your application If so, you must close that reader first. Even if your database is configured for MARS (multiple active result sets), it is not enabled by default, and is not currently supported by DLinq.



  • synthkid

    Ok - I've confirmed that this is a bug in our connection management. Below is a simple repro for the issue. The workaround in your case is to buffer the data you are assigning to ListBox.ItemsSource (as seen in the ToArray() call below). Whats happening is that when ListBox executes the query by iterating over the items, it opens a reader on the database. Later, SubmitChanges also attempts to open a reader on the connection (to retrieve database properties); normally our connection management forces any other open readers to buffer, but it isn't working in this case. I'll log a bug

    Northwind db = new Northwind("Server=<yourserver>");

    IEnumerable<Customer> enumerable = db.Customers;
    IEnumerator<Customer> enumerator = enumerable.GetEnumerator();

    // Use this instead as workaround
    //IEnumerable<Customer> enumerable = db.Customers.ToArray();

    Customer newCust = new Customer();
    newCust.CustomerID = "ABCD";
    newCust.CompanyName = "EFGH";
    db.Customers.Add(newCust);
    db.SubmitChanges();



  • markybark

    Can you show us some code

  • InvalidOperationException: open DataReader ...