This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Copy item from single-select to multi-select.

Former Member
Former Member
Hello, this is my first post, so thanks up front for whatever help anyone can give, and sorry for my lack of knowledge.

I am trying to copy the selection in a single-select property (iRollNumberProperty) to the selection in a multi-select property (iLandIDProperty) on the same object. The properties pull from two different Object Types which use identical queries to pull from the same external source (so, the unique IDs are the same in both Object Types).

I borrowed the AddUpdateProperty function from another topic, and used it without modification. The code is in the automatic value of an unrelated field.

I have used one specific case (129203000) to troubleshoot. The idea is to add the objectID "129203000" to the Land ID property to the object I was using as a test. When I trigger it, I get the error message that is attached. 344 is the ID of the Land ID object type, which is where the property value should be pulled from.

Hopefully my code will fill in the gaps where my explanation may be lacking. This is M-Files 2015.3.

Thanks.



Option Explicit

Dim iRollNumberProperty : iRollNumberProperty = 1432 '1432 is the Roll Number Property Definition
Dim iLandIDProperty : iLandIDProperty = 1747 '1747 is the LandID Property Definition
Dim objClientLookup: Set objClientLookup= PropertyValues.SearchForProperty(iLandIDProperty).TypedValue.GetValueAsLookup()

if IsNull(PropertyValues.SearchForPropertyEx(iLandIDProperty, true))=False then

    dim iRolls: iRolls = 129203000
    AddUpdateProperty iRolls, iLandIDProperty

end if


Function AddUpdateProperty(sValue, PROP_ID)

Dim oProperty : Set oProperty = CreateObject("MFilesAPI.PropertyValue")
oProperty.PropertyDef = PROP_ID
Dim iDataType : iDataType = Vault.PropertyDefOperations.GetPropertyDef(oProperty.PropertyDef).DataType
Dim iValue : iValue = CLng(sValue)
Dim oLookups : Set oLookups = PropertyValues.SearchForProperty(PROP_ID).TypedValue.GetValueAsLookups()
Dim oLookup : Set oLookup = CreateObject("MFilesAPI.Lookup")
Dim oCount

oCount = oLookups.Count
If oCount <> 0 then oCount = oCount + 1
oLookup.Item = iValue
oLookups.Add oCount, oLookup
PropertyValues.SearchForProperty(PROP_ID).TypedValue.SetValueToMultiSelectLookup oLookups
oProperty.TypedValue.SetValueToMultiSelectLookup oLookups
Vault.ObjectPropertyOperations.SetProperty ObjVer, oProperty
End Function
  • Former Member
    Former Member
    I have worked further on this, and perhaps my problem is not referring to the external ID for the object explicitly.

    I changed to the following:

    Option Explicit

    Dim iRollNumberProperty : iRollNumberProperty = 1432 '1432 is the Roll Number Property Definition
    Dim iRollNumbersProperty : iRollNumbersProperty = 1055 '1055 is the Roll Number(s) Property Definition
    Dim iLegalLandDescriptionProperty : iLegalLandDescriptionProperty = 1075 '1075 is the Legal Land Description Property Definition
    Dim iLegalLandDescriptionsProperty : iLegalLandDescriptionsProperty = 1041 '1075 is the Legal Land Description(s) Property Definition
    Dim iLandIDProperty : iLandIDProperty = 1747 '1747 is the LandID Property Definition
    Dim iRollInformationOBJID: iRollInformationOBJID = 106
    Dim iLandIDOBJID: iLandIDOBJID = 344
    Dim iVBScriptProperty: iVBScriptProperty = 1754

    Dim objClientLookup: Set objClientLookup= PropertyValues.SearchForProperty(iLandIDProperty).TypedValue.GetValueAsLookup()
    'Err.Raise MFScriptCancel, objClientLookup.DisplayValue & "-" & objClientLookup.DisplayID

    if IsNull (PropertyValues.SearchForPropertyEx(iLandIDProperty, true))=false then
    'if IsNull(PropertyValues.SearchForPropertyEx(iLandIDProperty, true)) then
    'Err.Raise MFScriptCancel, "got here"
    dim iRolls: iRolls = 129203000
    ' Output = "1"

    dim oValueListItem
    set oValueListItem = Vault.ValueListItemOperations.GetValueListItemByDisplayID(iLandIDOBJID , iRolls)
    'Err.Raise MFScriptCancel, oValueListItem.DisplayValue & "-" & oValueListItem.DisplayID
    Dim oPropValRelationship: Set oPropValRelationship = PropertyValues.SearchForProperty( iLandIDProperty )
    oPropValRelationship.Value.SetValue MFDatatypeMultiSelectLookup, oValueListItem.ID 'ID of the External object
    Vault.ObjectPropertyOperations.SetProperty ObjVer, oPropValRelationship


    ' AddUpdateProperty iRolls, iLandIDProperty

    end if


    Function AddUpdateProperty(sValue, PROP_ID)

    Dim oProperty : Set oProperty = CreateObject("MFilesAPI.PropertyValue")
    oProperty.PropertyDef = PROP_ID
    Dim iDataType : iDataType = Vault.PropertyDefOperations.GetPropertyDef(oProperty.PropertyDef).DataType
    Dim iValue : iValue = CLng(sValue)
    Dim oLookups : Set oLookups = PropertyValues.SearchForProperty(PROP_ID).TypedValue.GetValueAsLookups()
    Dim oLookup : Set oLookup = CreateObject("MFilesAPI.Lookup")
    Dim oCount

    oCount = oLookups.Count
    If oCount <> 0 then oCount = oCount + 1
    oLookup.Item = iValue
    oLookups.Add oCount, oLookup
    PropertyValues.SearchForProperty(PROP_ID).TypedValue.SetValueToMultiSelectLookup oLookups
    oProperty.TypedValue.SetValueToMultiSelectLookup oLookups
    Vault.ObjectPropertyOperations.SetProperty ObjVer, oProperty
    End Function


    I believe this might be working, but it seems to loop and then dies with the error message "maximum number of script executions exceeded" probably because I am doing this as an autocalculate on an unrelated property (called vbscript). Does this seem correct? So, basically, it runs initially because I add the "vbscript" property to the object (happens to be a multi-file document), and save the object. Then, unfortunately, it runs again because the object was modified by changing the value of the multi-select property, and runs again and again because of the same thing. I couldn't find anything that definitively tells me when the auto-calculate properties on an object cause an associated script to run.

    Right now, I am thinking I should run this in an event handler instead, but I only want it to run on the objects we add the "vbscript" property to. I'm not really sure what event handler would be appropriate if I go that way.

    Any input appreciated.
  • Dear DonO,

    I couldn't find anything that definitively tells me when the auto-calculate properties on an object cause an associated script to run.

    you can see execution order of scripts here: https://www.m-files.com/user-guide/latest/eng/execution_order_of_scripts.html?hl=order%2Cscripts
    you can see available event handlers here: https://www.m-files.com/user-guide/latest/eng/Event_handlers_variables.html?hl=event%2Chandlers

    The code is in the automatic value of an unrelated field.

    Why don't you write copying script into property definition that you are automatically calculating (LandID Property)? then you would not need to use SetProperty VaultObjectPropertyOperation in your code and copying would become as simple as:


    CONST ROLL_NUMBER_PD = 1432 'Single select where to copy from
    CONST LAND_ID_OBJTYPE = 344 ' Object Type of Land ID

    dim RollNumberPV: set RollNumberPV = PropertyValues.SearchForPropertyEx(ROLL_NUMBER_PD, true)

    if not IsNull(RollNumberPV) then 'Roll Number Property Definition exists on metadata card

    'Get selected Rollnumber as Lookup
    dim RollNumberLookup: set RollNumberLookup = RollNumberPV.Value.GetValueAsLookup()

    'Find LandID list item by DisplayID of selected Rollnumber
    dim LandIDListItem
    set LandIDListItem = Vault.ValueListItemOperations.GetValueListItemByDisplayID(LAND_ID_OBJTYPE , RollNumberLookup.DisplayID)

    'Owerwrite all existing selections with found single select value
    Output.SetValue MFDatatypeMultiselectLookup, LandIDListItem.ID

    end if


    In order to prevent "maximum number of script executions exceeded" from happening, you could check if property was already selected, if it is don't update property.
    Example how I would check if item is selected by creating IsItemSeleted function

    Option Explicit

    CONST ROLL_NUMBER_PD = 1432 'Single select where to copy from
    CONST LAND_ID_OBJTYPE = 344 ' Object Type of Land ID

    CONST LAND_ID_PD = 1747 'Multi select where to copy to

    dim LandIDPV: set LandIDPV = PropertyValues.SearchForPropertyEx(LAND_ID_PD, true)
    dim RollNumberPV: set RollNumberPV = PropertyValues.SearchForPropertyEx(ROLL_NUMBER_PD, true)

    if not IsNull(LandIDPV) then 'LandID property definition exists on meta-data card
    if not IsNull(RollNumberPV) then 'Roll Number property definition exists on meta-data card

    if not RollNumberPV.Value.IsNull() then 'Something is selected on Roll Number property

    'Get selected Roll number as Lookup
    dim RollNumberLookup: set RollNumberLookup = RollNumberPV.Value.GetValueAsLookup()

    'Find LandID list item by DisplayID of selected Roll Number
    dim LandIDListItem
    set LandIDListItem = Vault.ValueListItemOperations.GetValueListItemByDisplayID( LAND_ID_OBJTYPE , RollNumberLookup.DisplayID )

    if not IsItemSeleted( LandIDPV.Value, LandIDListItem.ID ) then 'This LandID is not already selected


    LandIDPV.Value.SetValue MFDatatypeMultiSelectLookup, LandIDListItem.ID 'Select/overwrite current selection with LandIDListItem.ID

    'or alternatively append selection with AppendSelection procedure defined below
    'AppendSelection LandIDPV.Value, LandIDListItem.ID, LAND_ID_OBJTYPE

    Vault.ObjectPropertyOperations.SetProperty ObjVer, LandIDPV 'Commit this propertyValue to current ObjVer
    end if
    end if
    end if
    end if

    'Check if provided itemID is selected in MultiSelectTypedValue
    function IsItemSeleted(MultiSelectTypedValue, ItemID )
    dim Result: Result = false

    if not MultiSelectTypedValue.IsNull() then
    dim Lookups: set Lookups = MultiSelectTypedValue.GetValueAsLookups()
    dim Lookup
    for each Lookup in Lookups
    if Lookup.Item = ItemID then
    Result = true
    Exit For
    end if
    next
    end if
    IsItemSeleted = Result
    end function

    'Append given itemID as selection of provided MultiSelectTypedValue. TypeID Is objectType ID of lookup
    sub AppendSelection(MultiSelectTypedValue, ItemID, TypeID )

    dim NewLookup: Set NewLookup = CreateObject("MFilesAPI.Lookup")

    NewLookup.ObjectType = TypeID
    NewLookup.Item = ItemID
    NewLookup.SetLatestVersion

    dim Lookups
    if MultiSelectTypedValue.IsNull() then
    set Lookups = CreateObject("MFilesAPI.Lookups")
    else
    set Lookups = MultiSelectTypedValue.GetValueAsLookups()
    end if

    Lookups.Add -1, NewLookup
    MultiSelectTypedValue.SetValueToMultiSelectLookup Lookups
    end sub




  • Former Member
    Former Member
    Wow - good information, thanks so much. I think the option to make the Land ID automatically calculate seems like a better approach.

    Thanks..
  • Former Member
    Former Member
    The second option will work like a charm. The property we are updating is a built-in, and we would need to create another property to be able to do the auto calculate, so the first option would require a bit more effort as the built-in property is already on the classes.

    Once again, thanks for the help!
  • Could anyone give me any idea how this might be adapted to take 3 single select properties and write them to one multi-select property?

    Much appreciated!
  • Dear clbeech,

    What have you tried? I don't understand what are you asking. Do the SetValue for 3 properties and call SetProperty in the end.
  • My company has three departments, which each have a section on the Metadata for each project containing the project manager for that department. I want to take the Project Manager from each department and compile a list of the 3 project managers in one field. Does that make sense?
  • Dear Clbeech,

    Thank you for taking time to explain.
    My recomendation stays same. Use second example.
    Get PropertyValues of those 3 properties, check if value is selected if it's not then append selection of multiselect.
    When done with all 3 do SetProperty ObjectPropertyOperation.

  • Thank you Tigu, and i've got that element to work, but what happens if I want any values removed that are not in the 3 values i'm writing to the object? I'd really appreciate some guidance on this.
  • Or perhaps there is a way to clear the list first before adding entries?