Author Topic: Best practices for simple lookup functions  (Read 9101 times)

0 Members and 1 Guest are viewing this topic.

Nathan Taylor

  • Guest

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Best practices for simple lookup functions
« Reply #16 on: January 14, 2007, 05:10:41 PM »
Hello Nathan,
Is that a translation of Tony's
Quote
public static ObjectId GetTableRecordId( ObjectId TableId, string Name )
From the Link posted here by Tim ?

You can post code here directly if you like .. :-)
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

Nathan Taylor

  • Guest
Re: Best practices for simple lookup functions
« Reply #17 on: January 14, 2007, 05:36:48 PM »
Hello Nathan,
Is that a translation of Tony's
Quote
public static ObjectId GetTableRecordId( ObjectId TableId, string Name )
From the Link posted here by Tim ?

You can post code here directly if you like .. :-)


Hi Kerry, Yes it is.

Code: [Select]
    Public Function GetTableRecordId(ByVal objTableId As ObjectId, ByVal strName As String) As ObjectId
        GetTableRecordId = ObjectId.Null
        Dim objDB As Database = objTableId.Database
        Dim objTrans As Transaction = objDB.TransactionManager.StartTransaction
        Dim objTable As SymbolTable = CType(objTrans.GetObject(objTableId, OpenMode.ForRead, False), SymbolTable)
        If objTable.Has(strName) Then
            Dim objID As ObjectId
            objID = objTable(strName)
            If objID.IsErased Then
                For Each objID In objTable
                    If Not objID.IsErased Then
                        Dim objSTR As SymbolTableRecord = CType(objTrans.GetObject(objID, OpenMode.ForRead, False), SymbolTableRecord)
                        If String.Compare(objSTR.Name, strName, True) = 0 Then
                            GetTableRecordId = objID
                            Exit For
                        End If
                    End If
                Next
            Else
                GetTableRecordId = objID
            End If
        End If
        objTrans.Commit()
        objTrans.Dispose()
    End Function

jmaeding

  • Bull Frog
  • Posts: 304
  • I'm just here for the Shelties.
Re: Best practices for simple lookup functions
« Reply #18 on: January 14, 2007, 07:03:01 PM »
so that would require it to be done in three steps right?
1) get the table ID
2) get the record objectID
3) cast it to the desired specific record type

I am wondering if its such a good idea to split things up so much.  I think that requires three transactions.
These patterns are so new to me, but I bet the arx crowd knows exactly how they like to organize subroutines like this.
That would sure be useful to hear a commentary on how experinced .net or arx'ers like to do things.

One thing I noticed is the code posted uses an ObjectId.Null as the default should the function not find what it was looking for.
Is that any better than using GetTableRecordId = nothing?  Why not return nothing rather than a null ObjectID?

With subroutines, you are always testing for valid returns.  I tend to test for nothing for object returns, and special values for number and string functions.  What do you guys typically do?

James Maeding

Nathan Taylor

  • Guest
Re: Best practices for simple lookup functions
« Reply #19 on: January 14, 2007, 07:51:01 PM »
so that would require it to be done in three steps right?
1) get the table ID
2) get the record objectID
3) cast it to the desired specific record type

I am wondering if its such a good idea to split things up so much.  I think that requires three transactions.
These patterns are so new to me, but I bet the arx crowd knows exactly how they like to organize subroutines like this.
That would sure be useful to hear a commentary on how experinced .net or arx'ers like to do things.

One thing I noticed is the code posted uses an ObjectId.Null as the default should the function not find what it was looking for.
Is that any better than using GetTableRecordId = nothing?  Why not return nothing rather than a null ObjectID?

With subroutines, you are always testing for valid returns.  I tend to test for nothing for object returns, and special values for number and string functions.  What do you guys typically do?

Here is a sample I posted at http://discussion.autodesk.com/thread.jspa?threadID=529533
Code: [Select]
    Private Sub Sample()
        AddRegAppTable("YourApplicationName")
    End Sub

    Private Sub AddRegAppTable(ByVal strAppName As String)
        Dim objDB As Database = HostApplicationServices.WorkingDatabase
        Dim objTrans As Transaction = objDB.TransactionManager.StartTransaction
        Dim objRAT As RegAppTable = CType(objTrans.GetObject(objDB.RegAppTableId, OpenMode.ForWrite, False), RegAppTable)
        Dim objRATR As RegAppTableRecord
        Dim objRATRID As ObjectId = GetTableRecordId(objDB.RegAppTableId, strAppName)
        If objRATRID = ObjectId.Null Then
            objRATR = New RegAppTableRecord
            objRATR.Name = strAppName
            objRAT.Add(objRATR)
            objTrans.AddNewlyCreatedDBObject(objRATR, True)
        End If
        objTrans.Commit()
        objTrans.Dispose()
    End Sub

The example might answer your questions if not I will explain.

Regards - Nathan

jmaeding

  • Bull Frog
  • Posts: 304
  • I'm just here for the Shelties.
Re: Best practices for simple lookup functions
« Reply #20 on: January 14, 2007, 09:41:05 PM »
I get the idea of avoiding passing objects and using id's instead, but the code posted is a sub.  I am wondering about functions that return things.
James Maeding

Nathan Taylor

  • Guest
Re: Best practices for simple lookup functions
« Reply #21 on: January 15, 2007, 05:09:11 PM »
I get the idea of avoiding passing objects and using id's instead, but the code posted is a sub.  I am wondering about functions that return things.
Hi James,

I understand you are trying to simplify things as much as possible. I think returning an ObjectID is the simplest option and would seem to be good paractice given all the AutoCAD methods use this approach. It is probably a bad idea to open an object with a transaction within a function and the return that object. Although if you still wanted to go down that route maybe passing the transaction to the function by reference might be the right approach. I am not overly experienced so take my advice with a grain of salt and I would be happy for others to comment.

I will comment my example to perhaps explain what I think better.

Code: [Select]
    Private Sub Sample()
        AddRegAppTable("YourApplicationName")
    End Sub

'Example adds a Record to the Registered Application Table if it does not exist
    Private Sub AddRegAppTable(ByVal strAppName As String)
        Dim objDB As Database = HostApplicationServices.WorkingDatabase
        Dim objTrans As Transaction = objDB.TransactionManager.StartTransaction

    'Get Registered Application table using existing Transaction
        Dim objRAT As RegAppTable = CType(objTrans.GetObject(objDB.RegAppTableId, OpenMode.ForWrite, False), RegAppTable)
        Dim objRATR As RegAppTableRecord

    'Get ObjectID of Record using posted GetTableRecordId fuction note how simple it is to get ObjectID of desired table using existing Datbase
        Dim objRATRID As ObjectId = GetTableRecordId(objDB.RegAppTableId, strAppName)

    'Test if Record existed note I don't know if there are any benefits using ObjectId.Null over Nothing but since there is a null value of the return type it makes sense to me to use it
        If objRATRID = ObjectId.Null Then

        'Record did not exist so create it
            objRATR = New RegAppTableRecord
            objRATR.Name = strAppName
            objRAT.Add(objRATR)
            objTrans.AddNewlyCreatedDBObject(objRATR, True)
        Else

        'Record exists although we are not using it get it for the example using existing transaction
            objRATR = CType(objTrans.GetObject(objRATRID, OpenMode.ForWrite, False), RegAppTableRecord)
        End If
        objTrans.Commit()
        objTrans.Dispose()
    End Sub

I hope that helps.

Regards - Nathan

jmaeding

  • Bull Frog
  • Posts: 304
  • I'm just here for the Shelties.
Re: Best practices for simple lookup functions
« Reply #22 on: January 15, 2007, 10:24:59 PM »
Interesting, I do like the flow of your code, that does not seem overly chopped up.
I am very interested in your comment on dealing with an object as opposed to an objectID. Somehow, that nags at me like it will come back to bite me (my method, not yours).
I am learning fast how sensitive acad is to an error in a dll.  I was crashing acad on stuff like converting color objects...

Thanks for the reply, we'll get to bullfrog status yet!
James Maeding

jmaeding

  • Bull Frog
  • Posts: 304
  • I'm just here for the Shelties.
Re: Best practices for simple lookup functions
« Reply #23 on: January 17, 2007, 01:47:47 PM »
by the way, got this code from ADN...answers my question on a generic lookup function:

Public Function getAnyObjNet(ByVal name As String, ByVal tableTypeId As ObjectId) As SymbolTableRecord
        Dim db As Database = HostApplicationServices.WorkingDatabase()
        Dim tm As Autodesk.AutoCAD.DatabaseServices.TransactionManager = db.TransactionManager
        Dim symTblRec As SymbolTableRecord = Nothing
        Using myT As Transaction = tm.StartTransaction()
            Try
                Dim symTbl As SymbolTable = myT.GetObject(tableTypeId, OpenMode.ForRead, False)

                If symTbl.Has(name) Then
                    symTblRec = myT.GetObject(symTbl.Item(name), OpenMode.ForRead)
                End If
                myT.Commit()
            Catch
                symTblRec = Nothing
            Finally
                myT.Dispose()
            End Try
        End Using
        Return symTblRec
    End Function

     'Example usage:
     'Define command 'test'
    <CommandMethod("test")> _
    Public Sub Asdkcmd1()
        ' Type your code here
        Dim db As Database = HostApplicationServices.WorkingDatabase
        Dim str As SymbolTableRecord = getAnyObjNet("*Model_Space", db.BlockTableId)

        Dim tm As Autodesk.AutoCAD.DatabaseServices.TransactionManager = db.TransactionManager
        Using myT As Transaction = tm.StartTransaction()
            If str.Name = "*Model_Space" Then
                Dim btr As BlockTableRecord = CType(str, BlockTableRecord)
            End If
        End Using
    End Sub

now that wasn't so hard was it? You just Use an * to tell it the string is meant as an object type.
James Maeding

jmaeding

  • Bull Frog
  • Posts: 304
  • I'm just here for the Shelties.
Re: Best practices for simple lookup functions
« Reply #24 on: January 17, 2007, 02:18:41 PM »
I guess that does not do what I was thinking, it still needs to grab the table outside and cast after.
It does answer a question though.
Notice that an object was returned by the getAnyObjNet function.
Then later, a transaction was opened, and the object cast to the desired type.
It seems it is ok to pass objects around, and do any changes within a transaction.

Note that the code does not commit or dispose of the transaction though, I think it needs to commit.  The Using method will dispose for us, but I think a commit is needed still.
James Maeding

Nathan Taylor

  • Guest
Re: Best practices for simple lookup functions
« Reply #25 on: January 17, 2007, 04:58:02 PM »
I guess that does not do what I was thinking, it still needs to grab the table outside and cast after.
It does answer a question though.
Notice that an object was returned by the getAnyObjNet function.
Then later, a transaction was opened, and the object cast to the desired type.
It seems it is ok to pass objects around, and do any changes within a transaction.

Note that the code does not commit or dispose of the transaction though, I think it needs to commit.  The Using method will dispose for us, but I think a commit is needed still.
The thing I don't like about the code is that the function is determining the OpenMode for the object. So the function is not as generic. Although you could pass the OpenMode as another parameter to the function.

Regards - Nathan

jmaeding

  • Bull Frog
  • Posts: 304
  • I'm just here for the Shelties.
Re: Best practices for simple lookup functions
« Reply #26 on: January 19, 2007, 12:09:34 PM »
oh, good point, I'll change that
James Maeding