0

I am using OleDbCommand to get a count of records in a table "Select count(MyField1) from MyTable". Using the following code.

SQL = "Select count(Field) from Table"
Dim DBcmd As New OleDbCommand(sql, _connection)
Return DBcmd.ExecuteReader

It locks the table so it can't be modified. I later try Alter Table MyTable Alter Column MyField2 Counter(1,1). MyField2 is an AutoNumber

I have tried to get around this with no luck. Anybody got any ideas?

All of this is with VB and an Access DB

I have tried using different connections but I always get the same error.

June7
  • 19,874
  • 8
  • 24
  • 34
  • 3
    Don't have this `_connection` in a class field. You must create, close, dispose of the connection in place. Create the `OleDbConnection` with the `Using` statement, it'll do all of that for you. Yes, don't keep the connection. See the third code block [here](https://stackoverflow.com/a/76612495/14171304) for example. – dr.null Aug 10 '23 at 16:01
  • Closing the connection every time fixed the problem for me. Thanks – Gary Wheeler Aug 10 '23 at 16:57
  • Does this answer your question? [how to count the number of records with ExecuteScalar if more than one then cannot insert into in the MS Access database on vb.net](https://stackoverflow.com/questions/76603281/how-to-count-the-number-of-records-with-executescalar-if-more-than-one-then-cann) – June7 Aug 10 '23 at 16:58
  • You certainly should close the connection but you probably didn't need to to solve this issue. You probably only needed to close the data reader. I don't see how it makes sense to return the reader when all you want is the count. You should have created the reader with a Using statement too and just returned the count. That's exactly what ExecuteScalar would do internally. – jmcilhinney Aug 11 '23 at 03:25

1 Answers1

0

When using ADO.NET, you should pretty much always create, use and destroy your data-access objects where you need them. If you create your own data access layer, that means doing so in each method that gets or saves data. In this case, you ought to create, use and destroy all three of the connection, command and data reader. It makes little sense to return the whole data reader when the code that receives it is then just going to have to get the count from it. It makes far more sense to get the count yourself and return that. You can then close the data reader yourself. It is almost certainly the open data reader that is locking your table, rather than the open connection. Closing the connection will close the data reader too but you ought to be doing that regardless.

Using connection As New OleDbConnection(_connectionString),
      command As New OleDbCommand(sql, connection)
    connection.Open()

    Using reader = command.ExecuteReader()
        reader.Read()

        Return reader.GetInt32(0)
    End Using
End Using

Note that the connection string is stored in a member field, rather than the connection. Each object that is created with a Using statement is disposed at the corresponding End Using statement. As demonstrated, you can use one Using block to handle multiple objects if you don't need any extra code between the creation of each and disposal of each.

Having said all that, you should not be using ExecuteReader in this case anyway. ExecuteScalar exists specifically to get the first column of the first row of the result set of a query, which is exactly what you want. It basically does what the code above does, i.e. creates a data reader and gets the first value, but letting that method do that work simplifies your code:

Using connection As New OleDbConnection(_connectionString),
      command As New OleDbCommand(sql, connection)
    connection.Open()

    Return CInt(command.ExecuteScalar())
End Using

The Using statement to create the connection and command are still the same. Note that it is fine to have a Return inside a Using block. The object(s) created will still be disposed no matter how you leave the Using block, even if an exception is thrown.

jmcilhinney
  • 50,448
  • 5
  • 26
  • 46