DbConnect CAO.GetLinks.count

DbConnect CAO.GetLinks.count

valdemiro.mendes
Contributor Contributor
412 Views
3 Replies
Message 1 of 4

DbConnect CAO.GetLinks.count

valdemiro.mendes
Contributor
Contributor
Hi folks,
I have a little problem with DbConnect...
My application (should) allows me to synchronize Block References (BR) with a Database Table (DT).
Synchronizing is not the problem.
The problem is I want to be able to Link the BR with DbConnect (create a Link programmatically), but it doesn't always work???
I have a sample DWG with 54 BR holding data to synchronize but without DbConnect Link Object (LO)
The amazing thing is that I test the app, sometimes it finds BR with LO and sometimes not!?!?
So, if I open the DWG, run the app, it will find that maybe BR nbr 20 or any other BR with 1 or even more LO.
If I close the DWG (without saving it), reopen it and restart the app then it will than other BR have LO's.
Every time I reopen the DWG and run the app, the result is different!?!?!?! Why???
The LinkTemplate just references the PK from the DataTable.
 
The app's part trying to link BR with LO runs as follow:
1. select all the Blocks and return them as array of ObjectIDs (PromptSelectionResult.Value.GetObjectIds())
2. loop each ObjectIDs
3. get the LO with CAO.GetLinks(LinkTemplate, ArrayOfOneObjectID, (int)CAO.LinkType.kEntityLinkType)
4. case LO.count == 0:
4.1. LinkTemplate.CreateLink(ArrayOfOneObjectID[0],CAO.KeyValues(TableFieldPKid, RecordID))
5. case LO.count == 1:
5.1. if LO.Item(0).KeyValues.Item(0).Value == RecordID then no need to change anything
5.2. if LO.Item(0).KeyValues.Item(0).Value != RecordID then change Value to RecordID
6. case LO.count > 1:
6.1. delete all LO which doesn't match RecordID
6.2. create new LO with RecordID
 
What's wrong with this?
Does the references to LOs change if create or modify one of them?
Why is LO.count different each time I reopen the DWG? This doesn't make sense!!!
 
The Form is divided in 3 sections:
TOP:
Select Block and Attribute to pair with LinkTemplate and FieldName
(checkboxes are not relevant for this problem)
LEFT:
Select which Attribute will be send to which Field in DataTable
RIGHT:
Select which Field from DataTable will change which Attribute Value
 

CapturePairBlocks.PNG

413 Views
3 Replies
Replies (3)
Message 2 of 4

Gepaha
Collaborator
Collaborator

Without seeing the code it is difficult to help.
Could you post the code where the problems occur (where you create the link, and modify the link).
When you create the link using CreateLink do you make sure that the link was actually created? CreateLink returns a Link object and do you make sure it is non-null?
ArrayOfOneObjectID[0] is the result of ObjectId.OldIdPtr.ToInt64()?
Don't forget that an entity can have several links with the same linktemplate but different KeyValues ​​so if you use multiple links you have to treat this correctly.
If you only use a single link and want to modify it, do you do it correctly? Use link.KeyValues ​​= keyValues?

0 Likes
Message 3 of 4

valdemiro.mendes
Contributor
Contributor

Here is the code: 

And here is what I get when I run t

public void LinkRecordsWithBlockReferences(acDb.ObjectId[] objIDs,
                                           string linkTemplateName,
                                           string blkRefAttribName,
                                           string tblFieldName)
{
  //if no Field name set, the exit
  if (tblFieldName != null)
  {
    tblFieldName = RemoveDelimiters(tblFieldName);
  }
  else
  {
    return;
  }

  using (acDb.Transaction tr = acApp.Core.Application.DocumentManager.MdiActiveDocument.Database.TransactionManager.StartTransaction())
  {
    //open the Data Table associated with the Link Template
    DataTable dt = _dbConn.GetDataTable(linkTemplateName);

    try
    {
      //DbConnect object
      CAO.DbConnect p_CAODbConn = new();

      //counter for  treated blocks
      int counter = 1;

      //name of Field holding the Record ID
      string tblFieldIDName = _dbConn.GetDbIdFieldNameFromLinkTemplate(linkTemplateName);

      //get LinkTemplate
      CAO.LinkTemplate activeLinkTemplate = p_CAODbConn.GetLinkTemplates().Item(linkTemplateName);

      //loop each Block
      foreach (acDb.ObjectId objID in objIDs)
      {
        // get the Block Reference
        acDb.BlockReference blkRef = null;
        blkRef = (acDb.BlockReference)tr.GetObject(objID, acDb.OpenMode.ForRead);

        //get value from Attribute
        string blkRefAttribValue = GetAttributeValueFromBlock(blkRef.AttributeCollection, blkRefAttribName);

        //search criteria
        string searchCriteria = ($"[{tblFieldName}] = '{blkRefAttribValue}'");

        //result for Linking operation
        string msgLinkingResult = "";

        //result coming from Linking event
        LinkResult linkingRecordResult = new();

        //get the Record for Field name dbFieldName = Field value <fldValue>
        DataRow[] drArr = null;
        drArr = dt.Select(searchCriteria);

        //how many records found?
        switch (drArr.Count())
        {
          case 0:
            ToCommandLine($"\nNo record found for: {searchCriteria}");
            break;

          case 1:
            //get record ID from DataTable
            int recIdInDataTable = (int)drArr[0][tblFieldIDName];

            //GetLinks just accepts an Array of Objects,
            //so add ObjectID to an Array of One Objects
            long[] arrOfOneObject = [(long)objID.OldIdPtr];

            //Links Object
            CAO.Links objLinks = null;

            try
            {
              //Objects linked with objID
              objLinks = p_CAODbConn.GetLinks(activeLinkTemplate, arrOfOneObject, (int)CAO.LinkType.kEntityLinkType);
            }
            catch (Exception ex)
            {
              Debug.Print($"ERROR trying to get Linked Objects {ex.Message}");
              return;
            }

            //KeyValues for new Link
            //normally there should only be a single Link Item
            CAO.KeyValues newKeyValues = objLinks.Count == 1 ? objLinks.Item(0).KeyValues : new();

            //new Link object in case we need to add a new one to the objLinks
            CAO.Link newLink = null;
            CAO.KeyValue newKeyValue = null;

            //try
            //{
            //what to do?
            switch (objLinks.Count)
            {
              case 0:
                Debug.Print($"Table Field name: {tblFieldIDName}={recIdInDataTable}");

                try
                {
                  //init new Link
                  newKeyValue = newKeyValues.Add(tblFieldIDName, recIdInDataTable);

                  // add new link
                  newLink = activeLinkTemplate.CreateLink(arrOfOneObject[0], newKeyValues);

                  //CreateLink succeded?
                  if (newLink != null)
                  {
                    //result
                    linkingRecordResult = LinkResult.NewCreated;
                    objLinks = null;

                    //maybe this helps?
                    acU.RegenEntity(objID);
                    acU.FlushGraphics();
                  }
                  else
                  {
                    Debug.Print($"Failed to create new Link for {tblFieldIDName}={recIdInDataTable}!\n");

                    //result
                    linkingRecordResult = LinkResult.Failed;
                  }
                }
                catch (Exception ex)
                {
                  Debug.Print($"LinkRecordsWithBlockReferences.CreateLink Failed. {ex.Message}");
                }
                break;

              case 1:
                int lnkExistingLinkedRecordID = 0;
                try
                {
                  //is there a recordID already linked to the Block reference?
                  lnkExistingLinkedRecordID = objLinks.Item(0).KeyValues.Item(0).Value;
                }
                catch (Exception ex)
                {
                  Debug.Print($"LinkRecordsWithBlockReferences.GetExistingLinkedRecordID Failed. {ex.Message}");

                  //result
                  linkingRecordResult = LinkResult.Failed;
                  break;
                }

                //debug what we have:
                Debug.Print($"\t{blkRefAttribName}: {blkRefAttribValue} Linked_ID = {lnkExistingLinkedRecordID}");
                Debug.Print($"\t{tblFieldName}:     {drArr[0][tblFieldName]} {tblFieldIDName} = {recIdInDataTable}");

                //if Existing Linked RecordID is different from RecordID in DataTable
                if (lnkExistingLinkedRecordID != recIdInDataTable)
                {
                  Debug.Print($"\t\told value = {objLinks.Item(0).KeyValues.Item(0).Value}");

                  //change value
                  dynamic valChangedTo = (objLinks.Item(0).KeyValues.Item(0).Value = recIdInDataTable);

                  Debug.Print($"\t\tnew value should now be {valChangedTo} vs {objLinks.Item(0).KeyValues.Item(0).Value}");

                  //result
                  linkingRecordResult = (int)valChangedTo == recIdInDataTable ? LinkResult.Changed : LinkResult.Failed;

                  //maybe this helps?
                  acU.RegenEntity(objID);
                  acU.FlushGraphics();

                  break;
                }
                else
                {
                  Debug.Print($"\tAlready linked: {objLinks.Item(0).KeyValues.Item(0).FieldName}={objLinks.Item(0).KeyValues.Item(0).Value}");

                  //result
                  linkingRecordResult = LinkResult.Exists;

                  break;
                }

              case int j when (j > 1):
                //to many links.
                string msgMoreThanOneLink = $"\n\tThe selected object: {objID} ({blkRefAttribName}={blkRefAttribValue}) has {objLinks.Count} Links associated with {linkTemplateName}.";
                msgMoreThanOneLink += "\n\tUse 'DbcLinkManager' to manage the references.";

                //there should only be ONE Link of associated with this Block Reference and LinkTemplate
                //delete all other Links
                foreach (CAO.Link linkToDelete in objLinks)
                {
                  if (linkToDelete.LinkType == CAO.LinkType.kEntityLinkType)
                  {
                    foreach (CAO.KeyValue key in linkToDelete.KeyValues)
                    {
                      msgMoreThanOneLink += $"\n\t\t({linkToDelete.Label}.{linkToDelete.LinkType}).{key.FieldName}={key.Value}";
                      if (key.Value != recIdInDataTable)
                      {
                        linkToDelete.Delete();
                        msgMoreThanOneLink += "\tDELETED";
                        break;
                      }
                    }
                  }
                }
                Debug.Print(msgMoreThanOneLink);

                //init new Link
                newKeyValue = newKeyValues.Add(tblFieldIDName, recIdInDataTable);

                newLink = activeLinkTemplate.CreateLink(arrOfOneObject[0], newKeyValues);

                //result
                linkingRecordResult = newLink != null ? LinkResult.Changed : LinkResult.Failed;

                //maybe this helps?
                acU.RegenEntity(objID);
                acU.FlushGraphics();

                break;
            }//end switch

            //message to display
            msgLinkingResult = $"({counter}) {blkRefAttribName} = {blkRefAttribValue} ";// linked to RecordID: '{recID}'";
            msgLinkingResult = linkingRecordResult switch
            {
              LinkResult.Failed => msgLinkingResult += "ERROR: failed to link ",
              LinkResult.NewCreated => msgLinkingResult += "new link with ",
              LinkResult.Changed => msgLinkingResult += "link changed to ",
              LinkResult.Exists => msgLinkingResult += "link exists. ",
              LinkResult.MoreThanOne => msgLinkingResult += "has more than one record linked with ",
              _ => msgLinkingResult += "****! something, which should, happend!"
            };

            msgLinkingResult += $"RecordID: {recIdInDataTable}.";
            ToCommandLine(msgLinkingResult);

            break;

          case int i when (i > 1):
            string msgMoreThanOneRecord = $"\nMore then one record found for: {searchCriteria}.";
            msgMoreThanOneRecord += $"\nCheck your Database Table and try again.";

            //Show content of drArr
            foreach (DataRow dr in drArr)
            {
              msgMoreThanOneRecord = "\n";
              foreach (object obj in dr.ItemArray)
              {
                msgMoreThanOneRecord += $"{obj}, ";
              }
              ToCommandLine($"\t: {msgMoreThanOneRecord}");
              Debug.Print($"\t: {msgMoreThanOneRecord}");
            }

            break;
        }//end switch

        //increment counter
        counter += 1;

        acU.FlushGraphics();
      }//end foreach
    }
    catch (Exception ex)
    {
      Debug.Print($"ERROR: LinkRecordsWithBlockReferences\n\t{ex.Message}");
    }

    //save changes
    tr.Commit();
    acU.FlushGraphics();
  }//end transaction
}//end LinkRecordsWithBlockReferences()

he Code:

 

Linking 54 blocks with Database (if needed):
(1) ATT_NUMLOC = B.E2-012 new link with RecordID: 1405.
(2) ATT_NUMLOC = B.E2-053 new link with RecordID: 1448.
(3) ATT_NUMLOC = B.E2-007 new link with RecordID: 1400.
(4) ATT_NUMLOC = B.E2-044 new link with RecordID: 1437.
(5) ATT_NUMLOC = B.E2-034 new link with RecordID: 1427.
(6) ATT_NUMLOC = B.E2-042 new link with RecordID: 1435.
(7) ATT_NUMLOC = B.E2-039 link changed to RecordID: 1432.
(8) ATT_NUMLOC = B.E2-036 new link with RecordID: 1429.
(9) ATT_NUMLOC = B.E2-016 new link with RecordID: 1409.
(10) ATT_NUMLOC = B.E2-015 new link with RecordID: 1408.
(11) ATT_NUMLOC = B.E2-009 new link with RecordID: 1402.
(12) ATT_NUMLOC = B.E2-001 new link with RecordID: 1394.
(13) ATT_NUMLOC = B.E2-006 new link with RecordID: 1399.
(14) ATT_NUMLOC = B.E2-032 link changed to RecordID: 1425.
(15) ATT_NUMLOC = B.E2-029 new link with RecordID: 1422.
(16) ATT_NUMLOC = B.E2-026 new link with RecordID: 1419.
(17) ATT_NUMLOC = B.E2-023 new link with RecordID: 1416.
(18) ATT_NUMLOC = B.E2-020 new link with RecordID: 1413.
(19) ATT_NUMLOC = B.E2-050 new link with RecordID: 1443.
(20) ATT_NUMLOC = B.E2-047 new link with RecordID: 1440.
(21) ATT_NUMLOC = B.E2-054 new link with RecordID: 1449.
(22) ATT_NUMLOC = B.E2-045 new link with RecordID: 1438.
(23) ATT_NUMLOC = B.E2-046 new link with RecordID: 1439.
(24) ATT_NUMLOC = B.E2-048 new link with RecordID: 1441.
(25) ATT_NUMLOC = B.E2-049 link changed to RecordID: 1442.
(26) ATT_NUMLOC = B.E2-051 new link with RecordID: 1444.
(27) ATT_NUMLOC = B.E2-052 new link with RecordID: 1445.
(28) ATT_NUMLOC = B.E2-021 new link with RecordID: 1414.
(29) ATT_NUMLOC = B.E2-022 new link with RecordID: 1415.
(30) ATT_NUMLOC = B.E2-024 new link with RecordID: 1417.
(31) ATT_NUMLOC = B.E2-025 new link with RecordID: 1418.
(32) ATT_NUMLOC = B.E2-027 link changed to RecordID: 1420.
(33) ATT_NUMLOC = B.E2-028 new link with RecordID: 1421.
(34) ATT_NUMLOC = B.E2-030 new link with RecordID: 1423.
(35) ATT_NUMLOC = B.E2-033 new link with RecordID: 1426.
(36) ATT_NUMLOC = B.E2-031 new link with RecordID: 1424.
(37) ATT_NUMLOC = B.E2-055 new link with RecordID: 2245.
(38) ATT_NUMLOC = B.E2-043 new link with RecordID: 1436.
(39) ATT_NUMLOC = B.E2-041 new link with RecordID: 1434.
(40) ATT_NUMLOC = B.E2-040 new link with RecordID: 1433.
(41) ATT_NUMLOC = B.E2-038 new link with RecordID: 1431.
(42) ATT_NUMLOC = B.E2-037 new link with RecordID: 1430.
(43) ATT_NUMLOC = B.E2-035 new link with RecordID: 1428.
(44) ATT_NUMLOC = B.E2-019 new link with RecordID: 1412.
(45) ATT_NUMLOC = B.E2-018 new link with RecordID: 1411.
(46) ATT_NUMLOC = B.E2-017 new link with RecordID: 1410.
(47) ATT_NUMLOC = B.E2-014 new link with RecordID: 1407.
(48) ATT_NUMLOC = B.E2-013 new link with RecordID: 1406.
(49) ATT_NUMLOC = B.E2-011 new link with RecordID: 1404.
(50) ATT_NUMLOC = B.E2-010 link changed to RecordID: 1403.
(51) ATT_NUMLOC = B.E2-003 new link with RecordID: 1396.
(52) ATT_NUMLOC = B.E2-002 new link with RecordID: 1395.
(53) ATT_NUMLOC = B.E2-004 link changed to RecordID: 1397.
(54) ATT_NUMLOC = B.E2-008 link changed to RecordID: 1401.

Synchronize finished.

 

But when I select the Blocks and click on "View Linked Records in Data View" in DbConnect I get:

Command: 49 record(s) are linked to 54 selected object(s).

Every time I run the code I get another result!!!???

What did I miss?

 

0 Likes
Message 4 of 4

Izhar_Azati
Advocate
Advocate

There seems to be a desire to sever the connection between entities in the drawing and an external database.
Not suitable when the direction is for everything to be in the cloud.
They continue to use OLEDB, which is not suitable for the .NET CORE environment, and the move to 64 bits also broke a lot of AUTODESK's code.
AUTODESK creates a copy of the linked table within the DWG, which really doesn't make sense.
I suggest using your XDATA, which has the parameters for linking to the record in the table in the database.
In recent years, if you try to connect the example file that comes with the software, to SQL SERVER for example - the system crashes.

0 Likes