Почему «MSysNavPaneGroupCategories» отображается в запросе .NET OleDbProvider для Access 2K db с критериями: ГДЕ MSysObjects.Name НЕ НРАВИТСЯ «MSys *» - PullRequest
1 голос
/ 07 января 2010

Я хочу перечислить все таблицы и их количество строк в базе данных MS Access, в виде сетки. Я использую запрос следующим образом:

SELECT MSysObjects.Name, CLng(DCount('*',[name])) AS RecordCount
    FROM MSysObjects WHERE (((MSysObjects.Type)=1)
    AND (MSysObjects.Name NOT LIKE 'MSys*')) 
    ORDER BY MSysObjects.Name;

В панели MS Access Query это работает просто отлично. Но когда я запускаю запрос через объект OleDbCommand в .NET, хотя запрос создает набор результатов, я получаю ряд данных с MSysNavPaneGroupCategories в нем. Эта строка всегда выдает ошибку, когда я пытаюсь:

 DataRow row = null;
 do
 {
    row = dt.NewRow();
    row["TableName"] = (string)dr["Name"];
    row["RecordCount"] = (int)dr["RecordCount"]; // Fails here when dr["Name"]==MSysNavPaneGroupCategories
    dt.Rows.Add(row);
 } while (dr.Read());

Сообщение об ошибке:

System.InvalidOperationException было необработанное.

Поставщик не может определить Значение Int32. Например, строка была только что создан, по умолчанию для Столбец Int32 не был доступен, и потребитель еще не установил новый Значение Int32. Источник = "System.Data"

Таким образом, мой обходной путь - СДЕЛАТЬ таблицу TEMP и вместо этого читать из нее (или установить значение по умолчанию для столбца ..., которое преодолевает ошибку, но все еще включает в себя таблицу мошенников в наборе результатов).

Что здесь происходит? MSysNavPaneGroupCategories не должен был даже превращаться в набор результатов.

В системной таблице MSysNavPaneGroupCategories не так много информации.

Этот URL говорит, что MSysNavPaneGroupCategories является одной из трех системных таблиц, которые

определить все содержимое в Панель навигации.

.. в Access 2007.

Этот Microsoft URL говорит

Панель навигации, новая в Microsoft Office Access 2007, является центральным место, из которого вы можете легко просмотреть и получить доступ ко всей вашей базе данных объекты (объекты базы данных: доступ База данных содержит такие объекты, как таблицы, запросы, формы, отчеты, страницы, макросы и модули. Доступ Проект содержит такие объекты, как формы, отчеты, страницы, макросы и модули.), запускать отчеты или вводить данные прямо в таблицах.

... в Access 2007.

Почему эта таблица должна отображаться в списке таблиц базы данных Access 2K, когда это функция Access 2007, и почему она вообще отображается в запросе, для которого она не соответствует критериям?

1 Ответ

0 голосов
/ 08 января 2010

Собственная библиотека доступа к данным Jet, DAO, предоставляет коллекцию TableDefs, которая должна облегчить получение учетных записей и запись данных в вашу сетку. Примерно так можно было бы выполнить работу в VBA (которая могла бы начать - это воздушный код):

  Dim db As DAO.Database
  Dim tdf As DAO.TableDef
  Dim strTableName As String
  Dim strConnect As String
  Dim strType As String 
  Dim strDatabase As String
  Dim strConnectType As String

  Set db = DBEngine.OpenDatabase("[path/filename of MDB/ACCDB file]")
  For Each tdf In db.TableDefs
    If (tdf.Attributes And dbSystemObject) = 0 Then ' examine only non-system tables
       strTableName = tdf.Name
       If Len(tdf.Connect) > 0 Then
          strConnect = tdf.Connect
          strDatabase = Split(strConnect, "=")(1)
       End If
       If (tdf.Attributes And dbAttachedTable) Then ' linked Jet/ACE table
          Debug.Print strTableName & ": " & DBEngine.OpenDatabase(strDatabase).TableDefs(strTableName).RecordCount
       ElseIf (tdf.Attributes And dbAttachedODBC) Then ' ODBC table
          Debug.Print strTableName & ": " & DBEngine(0)(0).OpenRecordset("SELECT COUNT(*) FROM " & strTableName)(0)
       Else ' local table
          Debug.Print strTableName & ": " & tdf.RecordCount
       End If
    End If
  Next tdf
  Set tdf = Nothing
  db.Close
  Set db = Nothing

Приведенный выше код обрабатывает только источники данных Jet / ACE и ODBC, но не электронные таблицы Excel, текстовые файлы / файлы CSV или DBF, но если они вам нужны, вы можете поместить случай ODBC в CASE ELSE и обрабатывать их все с помощью SELECT COUNT (*).

Вышесказанное также можно было бы явно оптимизировать, выполнив сначала все несистемные TableDefs и получив список всех уникальных серверных частей, так что вам придется делать OpenDatabase только один раз для каждого сервера Jet / ACE. Затем вы также можете использовать одно соединение ODBC с вашим источником данных ODBC или преобразовать строку соединения ODBC в ADO и получить больше информации, если вам нужно.

Теперь, является ли это хорошей идеей или нет, зависит от конкретной ситуации. Все TableDefs имеют свойство RecordCount, которое поддерживается как часть метаданных таблицы Jet / ACE. Но он доступен только для локальных таблиц, то есть не работает для связанных таблиц. Вот почему подключенные таблицы Jet / ACE проверяются на основании открытия внутренней базы данных.

Но, опять же, я обязательно говорю, что это лучший или даже хороший способ. Я просто выбрасываю это как пищу для размышлений, в основном потому, что мне нравится использовать преимущество свойства RecordCount (я полагаю, это то, что возвращается из таблицы SELECT COUNT (*) FROM), но быстрее, потому что вы этого не делаете есть накладные расходы на открытие набора записей), где он вам доступен.

...