How to attach a MSLink to an Element

Hi Everyone,

I am trying to write an MDL in C/C++ that should attach Meta-Data to Elements in an external MDB-Database.

I wrote already Code to make sure that the correct Database (DB) is attached, but now I have Problems how to attach the created MSLink to an element.

There is one function to write the Attributes into the DB and retrieve the MSLink:

Private int writeObjatt
(
UInt32   *mslink,  
char   *tableName, 
char   *objidP, 
char   *oclassP, 
char   *ocodeP,  
char   *icodeP, 
char   *statusP 
)
  {
 char   insertStmt[MAXSTATEMENTLENGTH];  
 char  dbColumns[5*TAGSTRINGVALLENGTH+10]; 
 char  dbValues[5*TAGSTRINGVALLENGTH+10]; 
 int   ret=-1, test1=-1;
 
 // Writing the column-names into a string
 sprintf(dbColumns, "objid, oclass, ocode, icode, status");
 
 // writing the values into a string
 sprintf(dbValues, "'%s','%s','%s','%s','%s'", objidP, oclassP, ocodeP, icodeP, statusP);
 
 // writing the finlal SQL-Insert-Statement into a string
 sprintf(insertStmt, "insert into %s (%s) values (%s)", tableName, dbColumns, dbValues);
 
 fprintf(f_log, "\t(In tab2db_writeObjatt): Insert-Statement= '%s'\n", insertStmt);
 
 // Writing into Database
 test1 = mdlDB_addRowWithMslink(mslink, tableName, insertStmt); 
 
 if(test1 == SUCCESS) ret=SUCCESS;
 
 return ret;
  }
I thought, that this would write the given Attributes into the DB and that I 'only' would have to attach this MSLink to an element. (The return-value from this function Shows 'SUCCESS' and the values are correctly written into the DB!). (There is an 'mscatalog' table defined in the DB and as well another table <tableName> that contains apart of the 'mslink'-column 5 other columns, defined as Texts[TAGSTRINGVALLENGTH]).
The Elements for which the Meta-data should be attached are handled in a Callback-function (from 'mdlScanCriteria_setElemRefCallback') that is shown below:
Private int CallbackFunct
(
ElementRef		elR,			
void			*callbackArg,	// Structur with arguments for Callback-function
ScanCriteriaP	scP				// Pointer to ScanCriteria-Object
) 
  {
	int		ret=SUCCESS;
	int 	test=-1, status=-1;
	int 	elType;			// Element-Typ
	UInt32		mslink;		// MSLink-Number
	CallbackArgStruct	*data = (CallbackArgStruct*)callbackArg;
	MSElementP	elP;	
	EditElemHandle eh(elR, mdlScanCriteria_getModel(scP));	// Element-Handler
	char t_objidP[TAGSTRINGVALLENGTH], t_oclassP[TAGSTRINGVALLENGTH], t_ocodeP[TAGSTRINGVALLENGTH];
	char t_icodeP[TAGSTRINGVALLENGTH], t_statusP[TAGSTRINGVALLENGTH];

	// Checking Element-Type
	elType = eh.GetElementType();

	// Pointer to element created from ElemeHandle
	elP = eh.GetElementP();

	if(elType==CELL_HEADER_ELM || elType==LINE_ELM || elType==LINE_STRING_ELM || elType==LINE_STRING_ELM) {
	
		[...]	// Retrieve Attribute-values from element

		// Writing Attributes into Database using the above mentioned function
		test = writeObjatt(&mslink, "objatt", t_objidP, t_oclassP, t_ocodeP, t_icodeP, t_statusP);
		
		//?????  How to attach the MSLink to the MSElement ?????//
		
		// REPLACING the old element instead of rewriting in reason of different Size after MSLink-Attachment ??
		status = ReplaceElement (elP);	//???
		
		if(test != SUCCESS) ret=-1;
	}
	return ret;
  }

So my Problem is, how I can attach the created MSLink to the Element it belongs to and how do I have to rewrite/replace it afterwards!
I tried to figure it out from the database-example 'gis.ma', but it seems to do something different in the sub-function 'gis_writeParcel', therefore I couldn't solve my Problem.
Many thanks for your help in advance,
Ines Wieland
Parents
  • Unknown said:
    I am trying to write an MDL in C/C++

    For what version of MicroStation?

    Unknown said:
    How to attach the MSLink to the MSElement?

    The DB interface is rather idiosyncratic.  Its terminology dates from Intergraph's hierarchical database from the 1980s, and doesn't match well with relational databases.

    Look at the MDL help about DatabaseLink.  It defines the struct with some comments.  What you need to do is to fill in a DatabaseLink with your data, then append that linkage to your element. 

    You may be able to use mdlDB_buildLink() to build a linkage, but either way use mdlElement_appendAttributes() to attach the linkage to your element.  Rewrite the element after attaching the linkage.

     
    Regards, Jon Summers
    LA Solutions

  • Hi Jon,

    many thanks for your answer, although my Problem is not solved yet.

    Im working on MicroStation V8i SS4.

    The structur of DatabaseLink is not very clear for me, e.g. what is meant with 'entity' in this context, is it the number of the table in mscatalog or the ElementID? And what do I have to fill in the LinkProps-structur and as dasType? In Addition I didn't found a function that uses the DatabaseLink-structure to append that linkage to an element.

    I tried the following inside the function 'writeObjatt', for which I added the Parameter 'MSElement *elP':

    Private int writeObjatt
    (
    MSElement		*elP,
    UInt32 *mslink,
    char *tableName,
    char *objidP,
    char *oclassP,
    char *ocodeP,
    char *icodeP,
    char *statusP
    )
     {
    	char insertStmt[MAXSTATEMENTLENGTH];
    	char dbColumns[5*TAGSTRINGVALLENGTH+10];
    	char dbValues[5*TAGSTRINGVALLENGTH+10];
    	int ret=-1, test1=-1, test2=-1, test3=-1;
    	short		link;
    	int			linkLength, linkType=OLEDB_LINKAGE, dasType=1;
    	LinkProps	props;
    	UInt32		newfilePos;
    
    	// Writing the column-names into a string
    	sprintf(dbColumns, "objid, oclass, ocode, icode, status");
    
    	//writing the values into a string
    	sprintf(dbValues, "'%s','%s','%s','%s','%s'", objidP, oclassP, ocodeP, icodeP, statusP);
    
    	// writing the final SQL-Insert-Statement into a string
    	sprintf(insertStmt, "insert into %s (%s) values (%s)", tableName, dbColumns, dbValues);
    
    	//Writing into Database
    	test1 = mdlDB_addRowWithMslink(mslink, tableName, insertStmt);
    
    	// Filling the LinkProps-Structur
    	props.information = NEWLINK; 	// new linkage generation mode ?
    	props.remote = DB_PROP_REMOTE;	// ??
    	props.modified = DB_PROP_MODIFIED;	//??
    	props.user = DB_PROP_USER;			// ??
    	props.linkageClass = OLEDB_ID;	//??
    	
    	test2 = mdlDB_buildLink(&link, &linkLength, linkType, &props, tableName, *mslink, dasType);
    	
    	test3 = mdlElement_appendAttributes(elP, linkLength, &link);  
    
    	newfilePos = mdlElement_rewrite(elP, NULL, mdlElement_getFilePos(FILEPOS_CURRENT, NULL));
    	
    
    
    if(test1 == SUCCESS && test3 == SUCCESS) ret=SUCCESS;
    
    return ret;
     }
    
    

    It can be compiled without Problem, but it crashes Microstation during the first element I am working on. The Problem seemed to be in line 43, where the function mdlElement_appendAttributes() is called.

    Is this in reason of wrong filled  LinkProps-structur and dasType, or did I misunderstood something else?

    Regards,

    Ines Wieland

  • It seems you have not correctly built the "link" structure, which is typically 4 or 8 words, depending on the linkage type. The "link" should be an array.

  • Unknown said:
    The structur of DatabaseLink is not very clear for me, e.g. what is meant with 'entity' in this context

    Yes, the terminology is obscure.  This article about MicroStation DB linkages may help.

    Entity No. is the integer associated with one of your DB tables in the mscatalog table.

    Displayable Attribrutes (DAS) are another obscure MicroStation term used with DBs.  MicroStation can automatically extract DB data and create text labels for elements having a DB linkage.  You need to be familiar with MicroStation DB user interface for that to make any sense!

    I've dug into our apps. for MicroStation V7, which is the last time I used MDL to create a DB element linkage.  This code is C, not C++, and has been superseded.

    First, some macro definitions...

    #define BAD_INDEX -1
    #define DBLINKAGE_ARRAY_SIZE 8
    /* // DB LinkProps initialisers // User bit is always 1 // Information bit is 1 to prevent new rows being inserted in DB on copy */ #define DB_LINKPROPS_INFORMATIONAL(p) \ memset (&p, 0x00, sizeof (LinkProps)); \ p.information = 1; \ p.user = 1; #define DB_LINKPROPS_NORMAL(p) \ memset (&p, 0x00, sizeof (LinkProps)); \ p.information = 0; \ p.user = 1;

    This used to work...

    int					db_createLinkage
    (
    short*                 linkage,	  //  <=  short [DBLINKAGE_ARRAY_SIZE]
    int                    linkType,  //  =>  ODBC_LINKAGE, ...
    ULong                  mslink,    //  =>  MSLINK we're going to attach
    char*                  pszTable	  //  =>  Name of DB table
    )
    {
        LinkProps          props;
        int                linkageSize = BAD_INDEX;
        int                rc;
        //   If MSLINK is zero, we don't want to attach a linkage.
        //   Set LinkageSize to -1 as a flag
        if (0L == mslink || NULL == pszTable || 0 == strlen (pszTable))
        {
            linkageSize = BAD_INDEX;
        }
        else
        {
            DB_LINKPROPS_INFORMATIONAL (props)
            rc = mdlDB_buildLink (
                linkage,            // <= database linkage
                &linkageSize,       // <= size (words) of linkage
                linkType,           // => ODBC_LINKAGE, etc, ...)
                &props,             // => properties of linkage
                pszTable,           // => table name of linkage
                mslink,             // => MSLINK key for linkage
                0);	                // => displayable attribute type
            if (SUCCESS == rc)
            {
    	    //TRACE3 ("  built DB linkage mslink=%ld to [%s] size=%d",
    	    //	mslink, pszTable, linkageSize);
            }
            else
            {
                //TRACE2 ("  failed to build DB linkage mslink=%ld to [%s]",
                //    mslink, pszTable);
                linkageSize = BAD_INDEX;
            }
        }
        return linkageSize;
    }

    Now you can attach the DB linkage to an element...

    boolean           db_appendLinkage
    (
    MSElementDescr**  ppFeature,		//  <=>	Attributed element
    ULong             mslink                //  =>  New MSLINK
    )
    {
        int           linkSize = 0;
        if (0L < mslink) {
            short 		linkage 	[DBLINKAGE_ARRAY_SIZE];
            //	Attach DB linkage to host shape
            linkSize = db_createLinkage (linkage, gp_dbInfo->dbLinkage,
                    mslink, tblFEATURE);
            //TRACE2 ("  mslink=%ld linkSize=%d",
            //	mslink, linkSize);
            mdlElmdscr_appendAttributes (ppFeature, linkSize, linkage);
    	//TRACE ("  created DB linkage");
        }
        return (0 < linkSize);
    }
    

     
    Regards, Jon Summers
    LA Solutions

    Answer Verified By: Ines Wieland 

Reply
  • Unknown said:
    The structur of DatabaseLink is not very clear for me, e.g. what is meant with 'entity' in this context

    Yes, the terminology is obscure.  This article about MicroStation DB linkages may help.

    Entity No. is the integer associated with one of your DB tables in the mscatalog table.

    Displayable Attribrutes (DAS) are another obscure MicroStation term used with DBs.  MicroStation can automatically extract DB data and create text labels for elements having a DB linkage.  You need to be familiar with MicroStation DB user interface for that to make any sense!

    I've dug into our apps. for MicroStation V7, which is the last time I used MDL to create a DB element linkage.  This code is C, not C++, and has been superseded.

    First, some macro definitions...

    #define BAD_INDEX -1
    #define DBLINKAGE_ARRAY_SIZE 8
    /* // DB LinkProps initialisers // User bit is always 1 // Information bit is 1 to prevent new rows being inserted in DB on copy */ #define DB_LINKPROPS_INFORMATIONAL(p) \ memset (&p, 0x00, sizeof (LinkProps)); \ p.information = 1; \ p.user = 1; #define DB_LINKPROPS_NORMAL(p) \ memset (&p, 0x00, sizeof (LinkProps)); \ p.information = 0; \ p.user = 1;

    This used to work...

    int					db_createLinkage
    (
    short*                 linkage,	  //  <=  short [DBLINKAGE_ARRAY_SIZE]
    int                    linkType,  //  =>  ODBC_LINKAGE, ...
    ULong                  mslink,    //  =>  MSLINK we're going to attach
    char*                  pszTable	  //  =>  Name of DB table
    )
    {
        LinkProps          props;
        int                linkageSize = BAD_INDEX;
        int                rc;
        //   If MSLINK is zero, we don't want to attach a linkage.
        //   Set LinkageSize to -1 as a flag
        if (0L == mslink || NULL == pszTable || 0 == strlen (pszTable))
        {
            linkageSize = BAD_INDEX;
        }
        else
        {
            DB_LINKPROPS_INFORMATIONAL (props)
            rc = mdlDB_buildLink (
                linkage,            // <= database linkage
                &linkageSize,       // <= size (words) of linkage
                linkType,           // => ODBC_LINKAGE, etc, ...)
                &props,             // => properties of linkage
                pszTable,           // => table name of linkage
                mslink,             // => MSLINK key for linkage
                0);	                // => displayable attribute type
            if (SUCCESS == rc)
            {
    	    //TRACE3 ("  built DB linkage mslink=%ld to [%s] size=%d",
    	    //	mslink, pszTable, linkageSize);
            }
            else
            {
                //TRACE2 ("  failed to build DB linkage mslink=%ld to [%s]",
                //    mslink, pszTable);
                linkageSize = BAD_INDEX;
            }
        }
        return linkageSize;
    }

    Now you can attach the DB linkage to an element...

    boolean           db_appendLinkage
    (
    MSElementDescr**  ppFeature,		//  <=>	Attributed element
    ULong             mslink                //  =>  New MSLINK
    )
    {
        int           linkSize = 0;
        if (0L < mslink) {
            short 		linkage 	[DBLINKAGE_ARRAY_SIZE];
            //	Attach DB linkage to host shape
            linkSize = db_createLinkage (linkage, gp_dbInfo->dbLinkage,
                    mslink, tblFEATURE);
            //TRACE2 ("  mslink=%ld linkSize=%d",
            //	mslink, linkSize);
            mdlElmdscr_appendAttributes (ppFeature, linkSize, linkage);
    	//TRACE ("  created DB linkage");
        }
        return (0 < linkSize);
    }
    

     
    Regards, Jon Summers
    LA Solutions

    Answer Verified By: Ines Wieland 

Children
  • Hi Jon,

    many thanks for your answer!

    This worked - I only had to rewrite the MSElementDescr-Object afterwards, so that the Linkage was written to the DGN-File.

    	
    UInt32  filePos=NULL, newfilePos=NULL;
    MSElementDescr* pFeature;   //used instead of MSElementDescr** ppFeature
    
    [...]   // see code from Jon
    
    mdlElmdscr_appendAttributes(&pFeature, linkSize, linkage);
    
    //rewriting the changed MSElementDescr-Oject
    filePos = mdlElmdscr_getFilePos(pFeature);
    newfilePos=mdlElmdscr_rewrite(pFeature, NULL, filePos);
    

    Many thanks for your help!

    Regards,

    Ines Wieland