You are viewing limited content. For full access, please sign in.

Question

Question

Using RA to create a document, assign a template and populate fields

SDK
asked on January 28, 2014

I have a requirerment (using RA only) to ceate a document in a folder, assign a template and populate fields with values.

 

I have a field list that may include fields that are not included on the template, and need to know how to create them on the document and assign their values.  In my field list, I do not know in advance whether the field exists on the template or is an additional field to be added.

 

Can anyone help with a code snippit please.
 

 

0 0

Replies

replied on January 28, 2014 Show version history

Hi Michael,

 

The below code snippet should do what you are looking for. Note that it is not completely tested, and it does not make any effort to catch exceptions. There are of course errors if invalid arguments are provided. I assume that you can create a Session object, have TIF images on disk to be used as pages and know their paths, and can create a Dictionary containing field names and values of the appropriate type. Let me know if you have any questions.

 

Edit: I have updated this code with the changes noted by Michael Allen in his reply. I changed the creation of the DocumentInfo to use DocumentInfo.Create instead of Document.Create, and I added a comment about the fact that a DocumentInfo is returned that must be disposed.

 

public static DocumentInfo CreateDocument(
    // The folder to create the document in
    string folderPath,
    // The name for the document
    string name,
    // The session to be used to create the document. Must be already authenticated
    Session lfSession, 
    // Paths to images on disk to use as the pages for the document. Assumed to be .tif
    List<string> pageFilePaths,
    // The name of the template to apply to the document
    string template,
    // A dictionary containing all of the fields to set and their values
    Dictionary<string, object> fields)
{

    // Find the requested parent folder
    FolderInfo parentFolder = Folder.GetFolderInfo(folderPath, lfSession);

    // Different creation method, as suggested by Michael Allen
    // Create the Document using DocumentInfo.Create
    DocumentInfo document = new DocumentInfo(lfSession);
    document.Create(
        parentFolder,
        name,
        // If you want to overwrite an existing file, or rename if there is a name conflict, use
        // EntryNameOption.Overwrite or EntryNameOption.AutoRename
        EntryNameOption.None);

    /* Old code. As noted by Michael Allen, it is more efficient to use the DocumentInfo.Create method (above)
        * than to use the Document.Create method and then construct a DocumentInfo object from the returned id.
        * 
        * // Create the document, and get a DocumentInfo object corresponding to the new document
        * int documentEntryId = Document.Create(
        *     parentFolder,
        *     name,
        *     // If you want to overwrite an existing file, or rename if there is a name conflict, use
        *     // EntryNameOption.Overwrite or EntryNameOption.AutoRename
        *     EntryNameOption.None,
        *     lfSession);
        * DocumentInfo document = Document.GetDocumentInfo(documentEntryId, lfSession);
        */

    // Loop through the image paths given. For each one, read the image into memory, create a new page in the
    // document, write the image to the page, and save the page.
    foreach (string pageFilePath in pageFilePaths)
    {
        byte[] image = File.ReadAllBytes(pageFilePath);
        PageInfo newPage = document.AppendPage();
        Stream pageStream = newPage.WritePagePart(PagePart.Image, image.Length);
        pageStream.Write(image, 0, image.Length);
        pageStream.Dispose();
        newPage.Save();
    }

    // Read the given field values into a FieldValueCollection
    FieldValueCollection fieldValues = new FieldValueCollection();
    foreach (string field in fields.Keys)
        fieldValues.Add(field, fields[field]);

    // Set the template on the document, and all of the field values. Note that items in the
    // FieldValueCollection need not be on the provided template
    document.SetTemplate(template, fieldValues);

    // Save and return the document
    document.Save();
    /* If you don't care about the DocumentInfo object after the document is created, you can have this method
        * not return anything (change the signature to public static void), and instead do
        * document.Dispose()
        * here. Otherwise, the caller is expected to call Dispose on the returned DocumentInfo object.
        */
    return document;
}

 

5 0
replied on January 28, 2014

Both Cliff Primmer's and Matthew Kelly's code samples look correct to me, although I didn't test them. Matthew's code sample returns a DocumentInfo instance, which the caller must eventually Dispose of, but otherwise they are very similar.

 

However, both examples don't create the document in the best way. In this instance, the best way to create the document is to use the DocumentInfo.Create method, rather than using Document.Create and then retrieving the DocumentInfo for the new document in a separate call. So, take either example, or combine them, but please use DocumentInfo.Create instead, and remember to call DocumentInfo.Dispose when you're done with it.

3 0
replied on January 28, 2014 Show version history

Michael (Allen),

 

Interesting in your example that in order to use the DocumentInfo.Create method you first have to instantiate the DocumentInfo object with the session as a parameter and then call its Create method to actually create the document in LF. 

 

As opposed to calling the Create method on the static Document object and then instantiating a DocumentInfo object with a call to the GetDocumentInfo method which Matthew and I proposed.

 

I thought I would do a little timer test so I used both options to create 100 new documents in LF and ran each test 5 times (total of 500 new documents for each method). 

 

  1. Using the DocumentInfo.Create method it took an average of 0.102 seconds to create each document.
  2. Using the static Document.Create method it took an average of 0.076 seconds to create each document.

 

I was surprised in that I assumed the DocumentInfo.Create method would be the faster option but for some reason it clearly is not. 

 

It would appear that both options have merit.  With that being said, is there a programmatic reason why we should not use the static Document object methods to create new documents?

0 0
replied on January 30, 2014

When you use DocumentInfo.Create, it's locked by the server upon creation, so you can safely modify the document while it's locked. If you use Document.Create followed by a lock, there's a window of time when it's unlocked. This sequence also generates two RELEASE notifications instead of one.

4 0
replied on January 28, 2014

Michael,

 

Here is an RA code snippet to create a new document, assign a template, and then assign metadata values.  The example is a bit contrived since I don't know how you building your field list and values.

 

        Try
            'Instantiate a repository registration and session object...
            Dim myRegistration As New RepositoryRegistration("localhost", "LFMAIN")
            Dim mySession As New Session

            'Login using password authorization...
            mySession.LogIn("admin", "admin", myRegistration)

            'Create the new document.  NOTE: See the SDK documentation for overloads of the create method...
            Dim docID As Integer = Document.Create("\NewDocument", "DEFAULT", EntryNameOption.AutoRename, mySession)

            'Get a reference to the DocumentInfo object...
            Dim docInfo As DocumentInfo = DirectCast(Entry.GetEntryInfo(docID, mySession), DocumentInfo)

            'Set the template for the new document...
            docInfo.SetTemplate("General")

            'Instantiate a new FieldValueCollection...
            Dim fvCollection As New FieldValueCollection

            'Add the metadata to the collection.  The first parameter is the field name and the
            'second parameter is the value.  NOTE: The value is type Object...
            fvCollection.Add("Document", "This is the document name")       'This field is part of the General template
            fvCollection.Add("Type", "This is the document type")           'So is this field...
            fvCollection.Add("Category", "This is the document category")   'And so is this one...
            fvCollection.Add("Incident Number", "13-12345")                 'This field is not part of the template...

            'Assign the fieldvalues to the DocumentInfo object...
            docInfo.SetFieldValues(fvCollection)

            'Persist the changes...
            docInfo.Save()

            'Cleanup...
            docInfo.Dispose()
            mySession.Close()
            fvCollection = Nothing
            mySession = Nothing
            myRegistration = Nothing

        Catch ex As Exception
            'Display any errors...
            MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK)

        End Try
 

 

As I mentioned, adding the fieldvalues is a bit contrived in this example.  In reality I would probably create a new class with two properties; FieldName and FieldValue.  The FieldName would be a String and the FieldValue would be an Object.  I would then populate a ListOf(myObject) to build the list of metadata fields and values and then do a For Each to actually add the values to the FieldValuesCollection.

 

Let me know if this helps or if you have any additional questions.

2 0
replied on January 28, 2014

Thanks to all -- I will experiment with the various approaches and provide feedback.  One question though -- if there are fields in the feledvaluecollection that are not on the template, will they be added to the document as additional "off-template" fields?

0 0
replied on January 29, 2014

Yes, any field that you add to the FieldValuesCollection that is not in the assigned template will show up in the extra fields section. 

 

It would appear from a programmatic perspective that the FieldValuesCollection is independent from the template that is assigned to the entry.  I assume that is intentional. 

 

I do notice that there is an overload on the FieldValuesCollection.Add method that you can specifically tell LF whether or not the field is part of the assigned template so I don't know if there is a performance advantage to using that overload if you know that at assignment time.  (My guess is that it does not matter and it is the LF client that has to decide where a field value displays when the document is actually opened)  Perhaps one of the engineers can provide feedback?

 

Good luck with your project!

1 0
replied on January 30, 2014

Thanks to all who contributed!  Oddly enough, I used a combination of all contributions (one of my next requirements was going to be adding pages -- which I found in one of the examples.

 

It's great that if a field exists in the fieldvalue collection that is not on the template it gets added as an additional field.  That's the exact result I wanted! 

 

Perfect!

0 0
You are not allowed to follow up in this post.

Sign in to reply to this post.