iBatis for .NET
  1. iBatis for .NET
  2. IBATISNET-104

QueryForXXX do not check cache before opening/closing connection

    Details

    • Type: Wish Wish
    • Status: Closed
    • Priority: Minor Minor
    • Resolution: Fixed
    • Affects Version/s: DataMapper 1.2.1
    • Fix Version/s: DataMapper 1.6
    • Component/s: DataMapper
    • Labels:
      None

      Description

      I was confused by SqlMapper opening and closing database connections even when items were cached. I thought that it was fetching results from the database, but when I looked at the source, it seemed like the QueryForXXX methods are opening connections, calling MappedStatement to fetch results and then closing connections. Perhaps opening/closing should be pushed to the MappedStatement Class so connections are used only when there's a cache miss.

        Activity

        Hide
        Gilles Bayon added a comment -

        In SVN

        Show
        Gilles Bayon added a comment - In SVN
        Hide
        Ron Grabowski added a comment -

        Changes to support SqlMapper.QueryForObject not opening/closing connections when dealing with CachingStatement objects:

        • Replaced StatementName with RequestScope in ExecuteEventArgs
        • Added PreExecute event that is raised before IDbCommand.Execute* methods
        • Changed QueryForObject to wire up PreExecute event if LocalSession is null
        • statement_PreExecute calls e.RequestScope.Session.OpenConnection() just before the query is executed

        I didn't alter the other Query* methods yet.

        Show
        Ron Grabowski added a comment - Changes to support SqlMapper.QueryForObject not opening/closing connections when dealing with CachingStatement objects: Replaced StatementName with RequestScope in ExecuteEventArgs Added PreExecute event that is raised before IDbCommand.Execute* methods Changed QueryForObject to wire up PreExecute event if LocalSession is null statement_PreExecute calls e.RequestScope.Session.OpenConnection() just before the query is executed I didn't alter the other Query* methods yet.
        Hide
        Ron Grabowski added a comment -

        Clinton suggested we do something like this:

        using (ISession session = new SqlMapSessionProxy(this.DataSource)

        { rows = statement.ExecuteUpdate(session, parameterObject); }

        and have the proxy intercept OpenConnection to actually open the connecction if there is a cache miss. I think this is easier and more relieable than the Pre and Post events and we shouldn't have to change other code in CachingStatement.cs

        Show
        Ron Grabowski added a comment - Clinton suggested we do something like this: using (ISession session = new SqlMapSessionProxy(this.DataSource) { rows = statement.ExecuteUpdate(session, parameterObject); } and have the proxy intercept OpenConnection to actually open the connecction if there is a cache miss. I think this is easier and more relieable than the Pre and Post events and we shouldn't have to change other code in CachingStatement.cs
        Hide
        Ron Grabowski added a comment -

        CachingStatement's ExecuteQueryForObject method uses this code to generate the appropriate CacheKey to check the cache:

        object obj = null;
        RequestScope request = this.Statement.Sql.GetRequestScope(
        parameterObject, session);
        _mappedStatement.PreparedCommand.Create(
        request, session, this.Statement, parameterObject);
        Cache.CacheKey cacheKey = this.GetCacheKey(request);
        cacheKey.Update("ExecuteQueryForObject");
        obj = this.Statement.CacheModel[cacheKey];

        The current implementation of Create() uses the session and an IDbCommand to construct the list of IDataParameters for the IDbCommand. Perhaps we could change the code in ApplyParameterMap to generate the IDbParameterCollection without requing an IDbCommand or IDbConnection. If we encounter a cache miss, an IDbCommand and IDbConnection would be created and the already calculated IDbParameterCollection would then be attached to the IDbCommand.

        Show
        Ron Grabowski added a comment - CachingStatement's ExecuteQueryForObject method uses this code to generate the appropriate CacheKey to check the cache: object obj = null; RequestScope request = this.Statement.Sql.GetRequestScope( parameterObject, session); _mappedStatement.PreparedCommand.Create( request, session, this.Statement, parameterObject); Cache.CacheKey cacheKey = this.GetCacheKey(request); cacheKey.Update("ExecuteQueryForObject"); obj = this.Statement.CacheModel [cacheKey] ; The current implementation of Create() uses the session and an IDbCommand to construct the list of IDataParameters for the IDbCommand. Perhaps we could change the code in ApplyParameterMap to generate the IDbParameterCollection without requing an IDbCommand or IDbConnection. If we encounter a cache miss, an IDbCommand and IDbConnection would be created and the already calculated IDbParameterCollection would then be attached to the IDbCommand.
        Hide
        Ron Grabowski added a comment -

        The offending code is most likely this snippet from SqlMapper.cs:

        if (session == null)

        { session = new SqlMapSession(this.DataSource); session.OpenConnection(); isSessionLocal = true; }

        IMappedStatement statement = GetMappedStatement(statementName);
        try

        { rows = statement.ExecuteUpdate(session, parameterObject); }

        catch

        { throw; }

        finally
        {
        if ( isSessionLocal )

        { session.CloseConnection(); }

        }

        IMappedStatement fires the Execute event when a query has been executed. Perhaps this idea could be extended to include PreExecute and PostExecute events that would open and close the connection to the database if the underlying MappedStatement is used when there is a cache miss:

        // create an open a SqlMapSession
        statement.PreExecute(statement_PreExecute);

        // close SqlMapSession
        statement.PostExecute(statement_PostExecute);

        rows = statement.ExecuteUpdate(session, parameterObject);

        Show
        Ron Grabowski added a comment - The offending code is most likely this snippet from SqlMapper.cs: if (session == null) { session = new SqlMapSession(this.DataSource); session.OpenConnection(); isSessionLocal = true; } IMappedStatement statement = GetMappedStatement(statementName); try { rows = statement.ExecuteUpdate(session, parameterObject); } catch { throw; } finally { if ( isSessionLocal ) { session.CloseConnection(); } } IMappedStatement fires the Execute event when a query has been executed. Perhaps this idea could be extended to include PreExecute and PostExecute events that would open and close the connection to the database if the underlying MappedStatement is used when there is a cache miss: // create an open a SqlMapSession statement.PreExecute(statement_PreExecute); // close SqlMapSession statement.PostExecute(statement_PostExecute); rows = statement.ExecuteUpdate(session, parameterObject);

          People

          • Assignee:
            Gilles Bayon
            Reporter:
            H. E. Sum
          • Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development