Projecting Stored Procedure resultset onto entity collection

Posts   
 
    
IObject
User
Posts: 35
Joined: 06-Jul-2006
# Posted on: 20-Jul-2006 23:21:07   

I'm trying to project the results of a stored procedure onto an entity collection and I'm getting an error.

I read the section Projecting Stored Procedure resultset onto entity collection in the documentation and modified my code as necessary to work for .net 2.

EntityCollection search = new EntityCollection(new EmployeeSearchEntityFactory());
            using(IRetrievalQuery query = RetrievalProcedures.GetFxAssociateSearchCallAsQuery(false, false, true, "ENE", false, "s", null, null, null))
            {
                using(DataAccessAdapter adapter = new DataAccessAdapter())
                {
                    using(IDataReader reader = adapter.FetchDataReader(query, CommandBehavior.CloseConnection))
                    {
                        List<IDataValueProjector> valueProjectors = new List<IDataValueProjector>();
                        IDataValueProjector i = new DataValueProjector(EmployeeSearchFieldIndex.Aident.ToString(), 0, typeof(int));
                        valueProjectors.Add(i);
                        DataProjectorToIEntityCollection2 projector = new DataProjectorToIEntityCollection2(search);
                        adapter.FetchProjection(valueProjectors, projector, query);
                    }
                }
            }

This is hitting the database, but the line

IDataReader reader = adapter.FetchDataReader(query, CommandBehavior.CloseConnection)

ives me a null reference exception. The query certainly exist because its hitting the database, and a new adapter is instantiated. Is there something I'm missing in my code that would cause this error?

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 21-Jul-2006 05:52:14   

Would you please post the stack trace of the exception you get?

IObject
User
Posts: 35
Joined: 06-Jul-2006
# Posted on: 21-Jul-2006 16:33:55   

Message:

Object reference not set to an instance of an object.

StackTrace:

   at SD.LLBLGen.Pro.ORMSupportClasses.Query.ToString()
   at SD.LLBLGen.Pro.ORMSupportClasses.RetrievalQuery.Execute(CommandBehavior behavior)
   at SD.LLBLGen.Pro.ORMSupportClasses.DataAccessAdapterBase.FetchDataReader(IRetrievalQuery queryToExecute, CommandBehavior readerBehavior)
   at TestHarness.Form1.button1_Click(Object sender, EventArgs e) in C:\\Visual Studio Solutions\\FX1\\TestHarness\\Form1.cs:line 108
   at System.Windows.Forms.Control.OnClick(EventArgs e)
   at System.Windows.Forms.Button.OnClick(EventArgs e)
   at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
   at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
   at System.Windows.Forms.Control.WndProc(Message& m)
   at System.Windows.Forms.ButtonBase.WndProc(Message& m)
   at System.Windows.Forms.Button.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
   at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
   at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
   at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
   at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
   at System.Windows.Forms.Application.Run(Form mainForm)
   at TestHarness.Program.Main() in C:\\Visual Studio Solutions\\FX1\\TestHarness\\Program.cs:line 17
   at System.AppDomain.nExecuteAssembly(Assembly assembly, String[] args)
   at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
   at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
   at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ThreadHelper.ThreadStart()
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39927
Joined: 17-Aug-2003
# Posted on: 21-Jul-2006 17:17:16   

Which trace flags have you enabled? ToString is called in trace actions only.

Frans Bouma | Lead developer LLBLGen Pro
IObject
User
Posts: 35
Joined: 06-Jul-2006
# Posted on: 21-Jul-2006 18:16:22   

Here is what I have enabled for tracing:

<system.diagnostics>
    <switches>
      <add name="SqlServerDQE" value="4" />
      <add name="ORMGeneral" value="4" />
      <add name="ORMStateManagement" value="4" />
      <add name="ORMPersistenceExecution" value="4" />
    </switches>
  </system.diagnostics>

I commented Diagnostics out, and got further along in the code, but I'm still getting a null reference exception on a new line of code:

adapter.FetchProjection(valueProjectors, projector, query);

Here is the StackTrace:

   at SD.LLBLGen.Pro.ORMSupportClasses.Query.ToString()
   at SD.LLBLGen.Pro.ORMSupportClasses.RetrievalQuery.Execute(CommandBehavior behavior)
   at SD.LLBLGen.Pro.ORMSupportClasses.DataAccessAdapterBase.FetchDataReader(IRetrievalQuery queryToExecute, CommandBehavior readerBehavior)
   at SD.LLBLGen.Pro.ORMSupportClasses.DataAccessAdapterBase.FetchProjection(List`1 valueProjectors, IGeneralDataProjector projector, IRetrievalQuery queryToExecute)
   at TestHarness.Form1.button1_Click(Object sender, EventArgs e) in C:\\Visual Studio Solutions\\FX1\\TestHarness\\Form1.cs:line 114
   at System.Windows.Forms.Control.OnClick(EventArgs e)
   at System.Windows.Forms.Button.OnClick(EventArgs e)
   at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
   at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
   at System.Windows.Forms.Control.WndProc(Message& m)
   at System.Windows.Forms.ButtonBase.WndProc(Message& m)
   at System.Windows.Forms.Button.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
   at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
   at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
   at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
   at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
   at System.Windows.Forms.Application.Run(Form mainForm)
   at TestHarness.Program.Main() in C:\\Visual Studio Solutions\\FX1\\TestHarness\\Program.cs:line 17
   at System.AppDomain.nExecuteAssembly(Assembly assembly, String[] args)
   at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
   at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
   at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ThreadHelper.ThreadStart()
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39927
Joined: 17-Aug-2003
# Posted on: 21-Jul-2006 20:31:53   

Ok, if you switch off the tracing flags, it should work as the tostring routine is then skipped. I'll check which flag makes the code crash. It's likely either ORMGeneral or ORMStateManagement as I haven't used these in a while myself.

Frans Bouma | Lead developer LLBLGen Pro
IObject
User
Posts: 35
Joined: 06-Jul-2006
# Posted on: 21-Jul-2006 23:34:18   

I changed my diagnostic settings to this

<system.diagnostics>
    <switches>
      <add name="SqlServerDQE" value="0" />
      <add name="ORMGeneral" value="0" />
      <add name="ORMStateManagement" value="0" />
      <add name="ORMPersistenceExecution" value="0" />
    </switches>
  </system.diagnostics>

and even tried commenting out the diagnostics and am still receiving the most recently posted error. Is there something I am missing or should be doing differently?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39927
Joined: 17-Aug-2003
# Posted on: 22-Jul-2006 09:42:43   

Checking the code, with the stacktrace, it doesn't seem to be tracing related. Here's RetrievalQuery.Execute:


public IDataReader Execute(CommandBehavior behavior)
{
    if(base.Command==null)
    {
        throw new InvalidOperationException("No Command present. Nothing to execute.");
    }

    if(base.Connection==null)
    {
        throw new InvalidOperationException("No Connection present. Cannot execute command.");
    }

    if(base.Connection.State != ConnectionState.Open)
    {
        throw new InvalidOperationException("The Connection is not in the prefered condition 'Open'. Cannot execute command.");
    }

    // execute the query
    try
    {
        IDataReader toReturn = base.Command.ExecuteReader(behavior);
        TraceHelper.WriteLineIf(TraceHelper.PersistenceExecutionSwitch.TraceVerbose, this, "Executed Sql Query");
        return toReturn;
    }
    catch(Exception ex)
    {
        // throw a catchable exception with detailed query information.
        throw new ORMQueryExecutionException(
            String.Format("An exception was caught during the execution of a retrieval query: {0}. Check InnerException, QueryExecuted and Parameters of this exception to examine the cause of this exception.", ex.Message), 
            base.ToString(), base.Parameters, ex);
    }
}

So the execution of the proc throws an exception but as you can see, the ToString() method in the catch clause also threw an exception (see stacktrace).

I'll see if I can trick a proc in throwing an exception and see why Tostring() fails.

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39927
Joined: 17-Aug-2003
# Posted on: 22-Jul-2006 12:32:23   

When a string parameter value is null, it fails when an exception occurs in the proc. (Reproduced).

Fixed in next build.

Frans Bouma | Lead developer LLBLGen Pro
IObject
User
Posts: 35
Joined: 06-Jul-2006
# Posted on: 24-Jul-2006 17:07:24   

Do you have an approximate date for the next release, or would you recommend coding around this for the time being?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39927
Joined: 17-Aug-2003
# Posted on: 24-Jul-2006 18:18:12   

This fix has been released. You can check which fixes are live by using the changelogs viewer in the customer area simple_smile

Frans Bouma | Lead developer LLBLGen Pro
IObject
User
Posts: 35
Joined: 06-Jul-2006
# Posted on: 24-Jul-2006 20:17:12   

Awesome, thanks so much!

IObject
User
Posts: 35
Joined: 06-Jul-2006
# Posted on: 24-Jul-2006 21:44:19   

Downloaded the new version, and I'm still getting an error on the same line of code:

Message:

An exception was caught during the execution of a retrieval query: There is already an open DataReader associated with this Command which must be closed first.. Check InnerException, QueryExecuted and Parameters of this exception to examine the cause of this exception.

StackTrace:

   at SD.LLBLGen.Pro.ORMSupportClasses.RetrievalQuery.Execute(CommandBehavior behavior)
   at SD.LLBLGen.Pro.ORMSupportClasses.DataAccessAdapterBase.FetchDataReader(IRetrievalQuery queryToExecute, CommandBehavior readerBehavior)
   at SD.LLBLGen.Pro.ORMSupportClasses.DataAccessAdapterBase.FetchProjection(List`1 valueProjectors, IGeneralDataProjector projector, IRetrievalQuery queryToExecute)
   at TestHarness.Form1.button1_Click(Object sender, EventArgs e) in C:\\Visual Studio Solutions\\FX1\\TestHarness\\Form1.cs:line 114
   at System.Windows.Forms.Control.OnClick(EventArgs e)
   at System.Windows.Forms.Button.OnClick(EventArgs e)
   at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
   at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
   at System.Windows.Forms.Control.WndProc(Message& m)
   at System.Windows.Forms.ButtonBase.WndProc(Message& m)
   at System.Windows.Forms.Button.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
   at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
   at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
   at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
   at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
   at System.Windows.Forms.Application.Run(Form mainForm)
   at TestHarness.Program.Main() in C:\\Visual Studio Solutions\\FX1\\TestHarness\\Program.cs:line 17
   at System.AppDomain.nExecuteAssembly(Assembly assembly, String[] args)
   at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
   at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
   at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ThreadHelper.ThreadStart()

Is there something I'm doing wrong?

Walaa avatar
Walaa
Support Team
Posts: 14995
Joined: 21-Aug-2005
# Posted on: 25-Jul-2006 06:05:54   

Are you sharing the DataAccessAdapter object among different threads? (DataAccessAdapter isn't thread-safe)

Also make sure your application is referencing the newly downloaded dlls.

IObject
User
Posts: 35
Joined: 06-Jul-2006
# Posted on: 25-Jul-2006 17:53:16   

The DataAccessAdapter is not being shared across threads, the only code being executed is the code listed above.

I double checked to make sure my project references were updated, and everything looked good.

Anything else I can do?

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39927
Joined: 17-Aug-2003
# Posted on: 25-Jul-2006 21:35:01   

Very weird...

My test:



/// <summary>
/// Test with multiple-resultset returning proc which is projected onto two entity collections (one per resultset)
/// </summary>
[Test]
public void ProcFetchProjectionToEntityCollections()
{
    EntityCollection<CustomerEntity> customers = new EntityCollection<CustomerEntity>( new CustomerEntityFactory() );
    EntityCollection<OrderEntity> orders = new EntityCollection<OrderEntity>( new OrderEntityFactory() );

    using( IRetrievalQuery query = RetrievalProcedures.GetCustomersAndOrdersOnCountryCallAsQuery( "Germany" ) )
    {
        using( DataAccessAdapter adapter = new DataAccessAdapter() )
        {
            using( IDataReader reader = adapter.FetchDataReader( query, CommandBehavior.CloseConnection ) )
            {
                // first resultset: Customers.
                List<IDataValueProjector> valueProjectors = new List<IDataValueProjector>();
                // project value on index 0 in resultset row onto customerid
                valueProjectors.Add( new DataValueProjector( CustomerFieldIndex.CustomerId.ToString(), 0, typeof( string ) ) );
                // project value on index 1 in resultset row onto companyname
                valueProjectors.Add( new DataValueProjector( CustomerFieldIndex.CompanyName.ToString(), 1, typeof( string ) ) );
                // resultset contains more rows, we just project those 2.
                DataProjectorToIEntityCollection2 projector = new DataProjectorToIEntityCollection2( customers );
                adapter.FetchProjection( valueProjectors, projector, reader );

                // second resultset: Orders. 
                valueProjectors = new List<IDataValueProjector>();
                valueProjectors.Add( new DataValueProjector( OrderFieldIndex.OrderId.ToString(), 0, typeof( int ) ) );
                valueProjectors.Add( new DataValueProjector( OrderFieldIndex.CustomerId.ToString(), 1, typeof( string ) ) );
                valueProjectors.Add( new DataValueProjector( OrderFieldIndex.OrderDate.ToString(), 3, typeof( DateTime ) ) );
                reader.NextResult();
                projector = new DataProjectorToIEntityCollection2( orders );
                adapter.FetchProjection( valueProjectors, projector, reader );

                reader.Close();
            }
        }
    }
    Assert.AreEqual( 11, customers.Count );
    Assert.AreEqual( 121, orders.Count );

    ResultsetViewer viewer = new ResultsetViewer();
    viewer.BindCollection( customers );
    viewer.ShowDialog();
    viewer.BindCollection( orders );
    viewer.ShowDialog();
}

Works ok.

Frans Bouma | Lead developer LLBLGen Pro
IObject
User
Posts: 35
Joined: 06-Jul-2006
# Posted on: 25-Jul-2006 22:06:24   

I forgot the most important line!

reader.Close();

Its working properly now, thanks for all the help!

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39927
Joined: 17-Aug-2003
# Posted on: 25-Jul-2006 22:47:52   

Aha! smile

Frans Bouma | Lead developer LLBLGen Pro