Записать объектные данные

Автор Тема: Записать объектные данные  (Прочитано 12119 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн Захаров МаксимАвтор темы

  • ADN OPEN
  • ***
  • Сообщений: 141
  • Карма: 3
Здравствуйте.
Вопрос скорее не по Civil3d а по Map3d. Просто нет в этом форуме ветки Map3d.
Пытаюсь присвоить примитиву объектные данные (OD). Код взял с просторов интернета (http://adndevblog.typepad.com/infrastructure/2012/05/adding-object-data-records-to-entity-using-map-3d-api.html)
Сделал функцию под себя. Идея проста, таблица создана необходимо ее присвоить объекту и записать свои данные. Данные содержатся в двухмерном массиве (0-имя поля, 1-значение). Раз 200 функция в цикле нормально срабатывает, потом все вылетает со следующим сообщением (Необработанное исключение типа "System.AccessViolationException" в ManagedMapApi.dll). Может кто подскажет как с этим бороться.
Код функции здесь, но это аналог вышеперчисленной ссылки
Код - vb.net [Выбрать]
  1. Public Shared Function FuncAddOD2(ByVal DataArray(,) As String, ByVal tableOBJ As ObjectData.Table, ByVal objID As ObjectId) As Boolean
  2.         FuncAddOD2 = False
  3.         If IsArray(DataArray) = False Then Exit Function
  4.         Try
  5.             Dim odRecords As ObjectData.Records = tableOBJ.GetObjectTableRecords(Convert.ToInt32(0), objID, Constants.OpenMode.OpenForRead, False)
  6.             Dim odRecord As ObjectData.Record = odRecords.Item(0)
  7.             odRecord = Autodesk.Gis.Map.ObjectData.Record.Create()
  8.             tableOBJ.InitRecord(odRecord)
  9.             Dim mapVal As Autodesk.Gis.Map.Utilities.MapValue
  10.             'читаем поля таблицы
  11.             Dim recTable As Autodesk.Gis.Map.ObjectData.FieldDefinitions = tableOBJ.FieldDefinitions 'читаем поля
  12.             For i As Integer = 0 To recTable.Count - 1
  13.                 Dim FieldItem As FieldDefinition = recTable.Item(i)
  14.                 Dim NameField As String = FieldItem.Name 'имя поля
  15.                 mapVal = odRecord(i)
  16.                 Dim boolFlag As Boolean = False
  17.                 For k As Integer = 0 To DataArray.GetUpperBound(1)
  18.                     Dim NameFl As String = DataArray(0, k) 'имя поля из массива
  19.                     Dim NewVAl As String = DataArray(1, k) 'значение которое необходимо записать
  20.                     If NameFl Like NameField Then 'если названия полей совпадают заносим значение
  21.                         If FieldItem.Type = Constants.DataType.Integer Then 'если это целое число
  22.                             Dim IntRec As Integer = Val(NewVAl)
  23.                             mapVal.Assign(IntRec)
  24.                             Exit For
  25.                         ElseIf FieldItem.Type = Constants.DataType.Real Then
  26.                             Dim IntRec As Double = Val(NewVAl)
  27.                             mapVal.Assign(IntRec)
  28.                             Exit For
  29.                         ElseIf FieldItem.Type = Constants.DataType.Character Then
  30.                             Dim IntRec As String = Val(NewVAl)
  31.                             mapVal.Assign(IntRec)
  32.                             Exit For
  33.                         Else
  34.                             mapVal.Assign(NewVAl)
  35.                             Exit For
  36.                         End If
  37.                     End If
  38.                 Next k
  39.             Next i
  40.             tableOBJ.AddRecord(odRecord, objID)
  41.             odRecord.Dispose()
  42.             odRecords.Dispose()
  43.             FuncAddOD2 = True
  44.         Catch ex As MapException
  45.         Catch ex As System.AccessViolationException
  46.         End Try
  47.     End Function

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Записать объектные данные
« Ответ #1 : 02-11-2017, 22:47:44 »
Для начала попробуй запустить оригинальную функцию в цикле > 200 раз. Если будет вылет, то скорее всего это баг.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Захаров МаксимАвтор темы

  • ADN OPEN
  • ***
  • Сообщений: 141
  • Карма: 3
Re: Записать объектные данные
« Ответ #2 : 03-11-2017, 10:15:32 »
Попробую конечно. Но вроде и так я полный аналог сделал.

Оффлайн Дмитрий Загорулькин

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 737
Re: Записать объектные данные
« Ответ #3 : 03-11-2017, 12:57:33 »
Непонятно. В строке 6 получаем первую запись из коллекции, а в строке 7 - создаём в эту же переменную новую запись. Зачем тогда получали запись? Если строка 6 лишняя, то и получать объект odRecords не имеет смысла. В исходном примере тоже этот непонятный момент присутствует.
Далее, вместо явного вызова Dispose лучше использовать конструкцию Using - так будет безопаснее.
Я пока не сильно вникал в суть кода, но, вроде как, получается, что при каждом вызове метода добавляется новая запись в таблицу (строки 7-8). 200 раз запись выполняется для одного объекта? Возможно, что есть какое-то ограничение по количеству записей.

Оффлайн Дмитрий Загорулькин

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 737
Re: Записать объектные данные
« Ответ #4 : 03-11-2017, 13:02:48 »
Данные содержатся в двухмерном массиве (0-имя поля, 1-значение).
А почему массив, а не словарь (Dictionary<string, string>)? Словарь гораздо удобнее - код более читаемый будет.

Оффлайн Дмитрий Загорулькин

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 737
Re: Записать объектные данные
« Ответ #5 : 03-11-2017, 13:27:05 »
Хм... А в строках 33-34 не погорячился? То есть, тип данных определить не удалось и выполняется запись "на авось"?

Оффлайн Захаров МаксимАвтор темы

  • ADN OPEN
  • ***
  • Сообщений: 141
  • Карма: 3
Re: Записать объектные данные
« Ответ #6 : 04-11-2017, 15:38:42 »
Спасибо за отклик Дмитрий.
Строки 6 и 7 полностью "слямзил" с примера.
Про Dispose - тоже сделал как в примере. А как должна выглядеть конструкция с Using?
Таблица данных (записи) добавляются для множества объектов. Суть программы чтение данных из xml. По данным xml сперва создается полилиния затем ей присваиваются OD данные. Если линий не очень много в файле то все ок, иначе ошибка. Может можно как то частями обрабатывать? Скажем обработать 200 полилиний, завершить программу и потом еще раз запустится, только конечно автоматически без участия пользователя? Полилинии создаются нормально, если отключить функцию записи OD данных все они рисуются.

Оффлайн Дмитрий Загорулькин

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 737
Re: Записать объектные данные
« Ответ #7 : 04-11-2017, 15:42:00 »
Я могу только на C# перевести и показать. В VB не силён. Устроит?

Оффлайн Захаров МаксимАвтор темы

  • ADN OPEN
  • ***
  • Сообщений: 141
  • Карма: 3
Re: Записать объектные данные
« Ответ #8 : 04-11-2017, 17:56:09 »
Давай, попробую.
Убрал 6 строку, вообще исключил строки c Dispose. Пока не помогает. Последнюю ветку условия Else то же убрал.

Оффлайн Дмитрий Загорулькин

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 737
Re: Записать объектные данные
« Ответ #9 : 06-11-2017, 12:53:28 »
Полилинии создаются нормально, если отключить функцию записи OD данных все они рисуются.
По моему опыту, это не всегда значит, что ошибка именно в этой части кода. Например, "за кадром" осталась работа с MapObjectData-таблицей. Как она открывается? Какое время она остаётся открытой? И т.п.
Вот примерно так я бы написал этот метод (проверять не на чем, поэтому, вообще не запускал):
Код - C# [Выбрать]
  1. using Autodesk.AutoCAD.DatabaseServices;
  2. using Autodesk.Gis.Map;
  3. using Autodesk.Gis.Map.ObjectData;
  4. using Autodesk.Gis.Map.Utilities;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Globalization;
  8. using MapCon = Autodesk.Gis.Map.Constants;
  9. using MapOD = Autodesk.Gis.Map.ObjectData;
  10. using System.Linq;
  11.  
  12. namespace C3dTest
  13. {
  14.     class ObjectDataTest
  15.     {
  16.         public static bool AddObjectData(Dictionary<string, string> dataDict, MapOD.Table table, ObjectId objId)
  17.         {
  18.             if (dataDict == null || dataDict.Count == 0) return false;
  19.             try
  20.             {
  21.                 // Создаём новую запись (используем конструкцию using вместо прямого вызова Dispose)
  22.                 using (MapOD.Record newRec = Record.Create())
  23.                 {
  24.                     // Приводим запись в соответствие с таблицей                  
  25.                     table.InitRecord(newRec);
  26.  
  27.                     // Получаем коллекцию описаний полей таблицы
  28.                     MapOD.FieldDefinitions fieldDefs = table.FieldDefinitions;
  29.  
  30.                     // Проходим по описаниям полей таблицы
  31.                     for (int i = 0; i < fieldDefs.Count; i++)
  32.                     {
  33.                         // Текущее описание
  34.                         FieldDefinition fieldDef = fieldDefs[i];
  35.  
  36.                         // Имя текущего описания поля
  37.                         string fieldName = fieldDef.Name;                        
  38.  
  39.                         // Пробуем получить из словаря данные с ключом,
  40.                         // соответствующим названию поля в таблице
  41.                         KeyValuePair<string, string> dataKeyValue = dataDict
  42.                             .FirstOrDefault(item => item.Key.Equals
  43.                             (fieldName, StringComparison.InvariantCultureIgnoreCase));
  44.  
  45.                         // Если не нашли - переходим к следующему описанию поля
  46.                         if (string.IsNullOrEmpty(dataKeyValue.Key)) continue;
  47.  
  48.                         // значение, которое необходимо записать  
  49.                         string dataValue = dataKeyValue.Value;                                                        
  50.  
  51.                         // если тип поля - целое число
  52.                         if (fieldDef.Type == MapCon.DataType.Integer)
  53.                         {
  54.                             // и если данные приводятся к целому числу
  55.                             int value;
  56.                             if (Int32.TryParse
  57.                                 (dataValue,
  58.                                 NumberStyles.Integer,
  59.                                 CultureInfo.InvariantCulture, out value))
  60.                             {                              
  61.                                 // записываем приведённое значение
  62.                                 newRec[i].Assign(value);
  63.                             }                          
  64.                         }
  65.                         // если тип поля - вещественное число
  66.                         else if (fieldDef.Type == MapCon.DataType.Real)
  67.                         {
  68.                             // и данные приводятся к вещественному числу
  69.                             double value;
  70.                             if (double.TryParse
  71.                                 (dataValue,
  72.                                 NumberStyles.Number,
  73.                                 CultureInfo.InvariantCulture,
  74.                                 out value))
  75.                             {
  76.                                 // записываем приведённое значение
  77.                                 newRec[i].Assign(value);
  78.                             }                            
  79.                         }
  80.                         // если тип поля - строка
  81.                         else if (fieldDef.Type == MapCon.DataType.Character)
  82.                         {
  83.                             // записываем строку
  84.                             newRec[i].Assign(dataValue);                          
  85.                         }
  86.                         // другие варианты не рассматриваем
  87.                         else
  88.                         {                            
  89.                         }
  90.                     }
  91.                     // добавляем запись в таблицу
  92.                     table.AddRecord(newRec, objId);
  93.                 }
  94.                 return true;
  95.             }
  96.             catch (MapException ex)
  97.             {
  98.             }
  99.             catch (System.AccessViolationException ex)
  100.             {
  101.             }
  102.             return false;
  103.         }
  104.  
  105.         //=======================================================
  106.         //Service provided by Telerik (www.telerik.com)
  107.         //Conversion powered by NRefactory.
  108.         //Twitter: @telerik
  109.         //Facebook: facebook.com/telerik
  110.         //=======================================================
  111.     }
  112. }
  113.  

Оффлайн Захаров МаксимАвтор темы

  • ADN OPEN
  • ***
  • Сообщений: 141
  • Карма: 3
Re: Записать объектные данные
« Ответ #10 : 06-11-2017, 19:38:29 »
Спасибо Дмитрий. Начало работы с таблицей простое
Код - vb.net [Выбрать]
  1. Dim mapApp As MapApplication = HostMapApplicationServices.Application
  2.                                       Dim activeProject As Project.ProjectModel = mapApp.ActiveProject
  3.                                         Dim tableList As ObjectData.Tables = activeProject.ODTables 'забираем таблицы
  4.                                         Dim tableOBJ As ObjectData.Table = mapApp.ActiveProject.ODTables.Item("CADASTRAL_PARCEL")
Таблица уже существует. Только добавляй записи. Сегодня выявил один интересный момент. После каждого вызова функции (FuncAddOD2), добавил диалог MsgBox со счетчиком. Пришлось поработать клавиатурой, но чудо программа отработала примерно 1300 раз, без всяких ошибок. Может таймер какой добавить?

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Записать объектные данные
« Ответ #11 : 06-11-2017, 20:25:15 »
Может таймер какой добавить?
Скорее не таймер, а вызов Application.DoEvents()
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн trir

  • ADN Club
  • ****
  • Сообщений: 475
  • Карма: 63
Re: Записать объектные данные
« Ответ #12 : 07-11-2017, 08:47:29 »

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Записать объектные данные
« Ответ #13 : 07-11-2017, 13:35:57 »
Раз 200 функция в цикле нормально срабатывает, потом все вылетает со следующим сообщением (Необработанное исключение типа "System.AccessViolationException" в ManagedMapApi.dll).
Случайно не 255 (или 256) раз?
У меня такое ощущение, что в строке:
Код - vb.net [Выбрать]
  1. Dim odRecords As ObjectData.Records = tableOBJ.GetObjectTableRecords(Convert.ToInt32(0), objID, Constants.OpenMode.OpenForRead, False)
объект открывается, но всё время происходят какие-то исключения (а в catch нет диагностической печати) и
Код - vb.net [Выбрать]
  1. odRecords.Dispose()
не вызывается.
Объект можно открыть для чтения только 255 раз. В следующий раз будет ошибка. Поэтому нужно не забывать его закрывать. Можно попробовать в явном виде  вызвать odRecords.Dispose() сразу, как только он становится ненужен.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Дмитрий Загорулькин

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 737
Re: Записать объектные данные
« Ответ #14 : 07-11-2017, 13:46:30 »
Судя по коду, этот объект совершенно не нужен. Не знаю, зачем его получают как в этом коде, так и в примере на ADNDevBlog.