Annotation Research Tool Application Code (EDM Sample Application)

The Annotation Research Tool Entity Data Model (EDM) application is implemented by using a Windows Form and controls from the Visual Studio toolbox.

A WebBrowser control is used to display Web references. Various textboxes enable users to enter information that becomes annotations and contact information. The URL strings that are assigned to the Locator property of Reference instances are obtained from the document object of the page that is displayed in the WebBrowser when instances of the ReferenceDescriptor class are created. Event handlers do all the work in response to user input. For a display that shows the UI, see Annotation and Research Collaboration Tool (EDM Sample Application).

Exe.Config File and Connection String

The following exe.config file contains the connection string and configuration information for a SQL Server or SQL Server Compact 3.5 SP1 database. The System.Data.EntityClient namespace that contains classes used by the connection and metadata is also referenced.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <connectionStrings>
    <add name="ResearchCollaborationData"
         connectionString="metadata=.;
             provider=System.Data.SqlClient;
             provider connection string='server=servername;
             database=ResearchCollaborationData;
             integrated security=true;
             multipleactiveresultsets=true'"
         providerName="System.Data.EntityClient"/>
  </connectionStrings>
</configuration>

Note

This connection string sets multiple active result sets to true as required to invoke the Load method on associations when another data reader is already open on the same connection.

Initializing the Connection to Storage

With the previous exe.config file in scope of the executable and a reference to System.Data.Entity.dll in the project, one line of code is sufficient to open a connection to data that is used by this application.

    ResearchCollaborationData researchCollaborationData =
                                    new ResearchCollaborationData();

All event handlers used to query or update data by this application use this initialization. The connection is closed with the following statement:

    researchCollaborationData.Connection.Close();

Creating a Reference Descriptor

The following code creates an instance of the ReferenceDescriptor class and saves it to storage. The sequence determines whether the page in the WebBrowser window already exists as a Reference object. If it does not exist, a new instance of Reference is created with the ReferenceDescriptor. If the Reference is not already in storage, it is added by calling AddToReference: researchCollaborationData.AddToReferecne(newReference). The ReferenceDescriptor is added to storage by calling researchCollaborationData.AddToReferenceDescriptor(newReferenceDescriptor).

The ReferenceDescriptor is also added to the collection represented by the navigation property of the Reference named RefDescriptors: newReference.RefDescriptors.Add(newReferenceDescriptor).

The application does not implement a method for creating a Reference instance without an associated ReferenceDescriptor.

        private void buttonCreateRefDescriptor_Click(
            object sender, EventArgs e)
        {
            ResearchCollaborationData researchCollaborationData = null;
            try
            {
                using (researchCollaborationData =
                    new ResearchCollaborationData())
                {
                    ObjectParameter param = new ObjectParameter(
                        "p", webBrowser1.Document.Url.ToString());

                    if (!researchCollaborationData.Reference.Where(
                        "it.Locator = @p", param).Any())
                    {
                        Reference newReference = new Reference();
                        newReference.ReferenceID = Guid.NewGuid(); 
                        newReference.Locator = webBrowser1.Document.Url.ToString();

                        researchCollaborationData.AddToReference(newReference);

                        ReferenceDescriptor newReferenceDescriptor =
                             new ReferenceDescriptor();
                        newReferenceDescriptor.DescriptorID = Guid.NewGuid();

                        newReferenceDescriptor.Keyword = 
                            textBoxKeyWord.Text;

                        newReferenceDescriptor.Annotation = 
                            textBoxAnnotationResults.Text;

                        researchCollaborationData.AddToReferenceDescriptor(newReferenceDescriptor);

                        newReference.RefDescriptors.Add(
                            newReferenceDescriptor);
                    }
                    else
                    {
                        Reference reference = 
                            researchCollaborationData.Reference.Where(
                            "it.Locator = @p", param).First();

                        ReferenceDescriptor newReferenceDescriptor = 
                            new ReferenceDescriptor();
                        newReferenceDescriptor.DescriptorID = Guid.NewGuid();

                        newReferenceDescriptor.Keyword = 
                            textBoxKeyWord.Text;

                        newReferenceDescriptor.Annotation = 
                            textBoxAnnotationResults.Text;
                        researchCollaborationData.AddToReferenceDescriptor(newReferenceDescriptor);

                        reference.RefDescriptors.Add(
                            newReferenceDescriptor);
                    }

                    researchCollaborationData.SaveChanges();
                    

                    researchCollaborationData.Connection.Close();
                }
            }
            catch(Exception exception)
            {
                MessageBox.Show(exception.ToString());
                researchCollaborationData.Connection.Close();
            }
        }

Creating a ContactPerson Instance

Creating a new ContactPerson instance and associating it with a Reference follows the same procedure as creating a ReferenceDescriptor and associating it with a Reference. There are four possible code options depending on whether one or both ContactPerson and Reference already exist. In the former case of creating a ReferenceDescriptor, a new descriptor instance is always created. The process of associating a ContactPerson with a Reference determines whether an instance of ContactPerson already represents this contact.

A ReferenceDescriptor is associated with only one Reference, whereas a ContactPerson can be associated with many References. For more information about implementing the many-to-many Association that supports this relationship, see Annotation Research Tool Schemas (EDM Sample Application).

The four code paths in the following event handler all connect instances of the ContactPerson entity with instances of the Reference entity. The first option creates both a new ContactPerson and a new Reference. The new ContactPerson and new Reference are added to storage using AddToContactPerson and AddToReference. Because this is a many-to-many association, a new link entity must also be instantiated and its navigation properties initialized to connect instances of ContactPerson and Reference.

                    ContactPersonReference newLink = 
                        new ContactPersonReference();
                    newLink.ContactPersonRefID = Guid.NewGuid();

                    newLink.RelatedContact = newContact;
                    newLink.RelatedReference = newReference;

This code sequence instantiates the link entity named ContactPersonReference. The link entity has navigation properties representing the two ends of the association: RelatedContact and RelatedReference. These are assigned the new instances of ContactPerson and Reference that have been created in this code path. In other cases, where either or both the ContactPerson or Reference already exits, the assignments use existing instances that have been located by object queries.

The new link entity is added to storage and all new entity instances are saved in the following code.

        researchCollaborationData.AddToContactPersonReference(newLink);
        researchCollaborationData.SaveChanges();

Two of the four possible code paths are shown in the following sequence. For the complete event handler, see method: private void buttonCreateRefPerson_Click(object sender, EventArgs e) in the complete event-handler code.

                    ObjectParameter paramContact = 
                        new ObjectParameter("p", textBoxEmail.Text);

                    if (!researchCollaborationData.ContactPerson.Where(
                        "it.Email = @p", paramContact).Any())
                    {
                        ObjectParameter paramReference = 
                            new ObjectParameter("p", 
                            webBrowser1.Document.Url.ToString());

                        if (!researchCollaborationData.Reference.Where(
                            "it.Locator = @p", paramReference).Any())
                        {
                            // Neither contact nor reference exist.
                            ContactPerson newContact = new ContactPerson();
                            newContact.ContactPersonID = Guid.NewGuid(); 
                            newContact.LastName = textBoxLastName.Text;
                            newContact.FirstName = textBoxFirstName.Text; 
                            newContact.Email = textBoxEmail.Text;

                            newContact.Title = 
                                textBoxTitlePosition.Text;

                            researchCollaborationData.AddToContactPerson(newContact);

                            Reference newReference = new Reference();
                            newReference.ReferenceID = Guid.NewGuid(); 
                            newReference.Locator = webBrowser1.Document.Url.ToString();

                            researchCollaborationData.AddToReference(newReference);

                            ContactPersonReference newLink = 
                                new ContactPersonReference();
                            newLink.ContactPersonRefID = Guid.NewGuid();

                            newLink.RelatedContact = newContact;
                            newLink.RelatedReference = newReference;
                            researchCollaborationData.AddToContactPersonReference(newLink);
                        }

                        else
                        {
                            // Reference exists but contact doesn't.
                            Reference reference = 
                                researchCollaborationData.Reference.
                                Where("it.Locator = @p", 
                                paramReference).First();

                            ContactPerson newContact = new ContactPerson();
                            newContact.ContactPersonID = Guid.NewGuid(); 
                            newContact.LastName = textBoxLastName.Text;
                            newContact.FirstName = textBoxFirstName.Text; 
                            newContact.Email = textBoxEmail.Text;

                            newContact.Title = 
                                textBoxTitlePosition.Text;

                            researchCollaborationData.AddToContactPerson(newContact);

                            ContactPersonReference newLink = new ContactPersonReference();
                            newLink.ContactPersonRefID = Guid.NewGuid();
                            newLink.RelatedContact = newContact;
                            newLink.RelatedReference = reference;
                            researchCollaborationData.AddToContactPersonReference(newLink);

                        }
                    }

Use Reference Descriptors to Search for References

Instances of the ReferenceDescriptor entity are annotations used to describe and locate Web resources so that research does not have to be repeated or catalogued someplace else. Each ReferenceDescriptor represents a single annotation. Many instances of ReferenceDescriptor can describe a Web page, but each instance can only be associated with one page.

Web references are annotated by adding ReferenceDescriptor instances as described in the previous code segments. Searching the Annotation and Keyword properties of ReferenceDescriptor instances provides a means to relocate useful Reference pages. The following event handler is engaged when the user enters keywords or a search phrase in the search text box and clicks the Find button.

        private void buttonSearch_Click(object sender, EventArgs e)
        {
            ResearchCollaborationData researchCollaborationData = null;
            try
            {
                using (researchCollaborationData = 
                    new ResearchCollaborationData())
                {
                    // Make a list of keywords to search for in annotatations.
                    List<string> keywords = new List<string>();
                    int i = 0;
                    int j = 0;
                    while (i < textBoxSearch.Text.Length)
                    {
                        j = textBoxSearch.Text.IndexOf(" ", i);
                        if (-1 == j) j = textBoxSearch.Text.Length;

                        keywords.Add(
                             textBoxSearch.Text.Substring(i, j - i));

                        i = ++j;
                    }

                    textBoxAnnotationResults.Text = "Results:";
                    foreach (string keyword in keywords)
                    {
                        // Create ObjectParameter from each keyword.
                        ObjectParameter paramKeyword = 
                            new ObjectParameter(
                            "p", "%" + keyword + "%");

                        ObjectQuery<ReferenceDescriptor> 
                            descriptorQuery = 
                            researchCollaborationData.
                            ReferenceDescriptor.Where(
                            "it.Annotation LIKE @p OR it.Keyword LIKE @p",
                            paramKeyword);

                        foreach (ReferenceDescriptor refDescriptor
                                                  in descriptorQuery)
                        {

                            textBoxAnnotationResults.Text = 
                                textBoxAnnotationResults.Text + "\n" +
                                refDescriptor.Keyword + "\n" + 
                                refDescriptor.Annotation;

                           refDescriptor.ReferenceReference.Load();

                            Reference reference = refDescriptor.Reference;

                            textBoxAnnotationResults.Text = 
                                textBoxAnnotationResults.Text + "\n" +
                                reference.Locator + "\n";

                            foreach (ContactPersonReference contactPersRef in
                                researchCollaborationData.ContactPersonReference)
                            {
                                contactPersRef.RelatedReferenceReference.Load();
                                if (contactPersRef.RelatedReferenceReference.Value.Equals(
                                    reference))
                                {
                                    contactPersRef.RelatedContactReference.Load();

                                    textBoxAnnotationResults.Text =
                                    textBoxAnnotationResults.Text +
                                    "\n" +
                                    "Relevant Contact:";

                                    textBoxAnnotationResults.Text =
                                        textBoxAnnotationResults.Text +
                                        "\n" +
                                        contactPersRef.
                                        RelatedContact.FirstName + " " +
                                        contactPersRef.RelatedContact.
                                        LastName +
                                        " Title: " + contactPersRef.
                                        RelatedContact.Title + " Email: "
                                        + contactPersRef.RelatedContact.
                                        Email
                                        + "\n";
                                }
                            }                            
                        }                        
                    }
                }
            }
            catch (Exception exception)
            {
                MessageBox.Show(exception.ToString());
            }
            
        }

This code consists of two basic sequences: one to create a List<T> of search strings and another to query for matching text in the Keyword and Annotation properties of ReferenceDescriptor instances.

Creating the list of search strings is accomplished by parsing the input text. The query is a parameterized ObjectQuery used in a loop that inserts each search string into the query and compares it to the texts assigned to the Keyword and Annotation properties of instances of ReferenceDescriptor in storage. The ObjectParameter and ObjectQuery classes are instantiated in the following code segment.

               // Create ObjectParameter from each keyword.
               ObjectParameter paramKeyword = 
                    new ObjectParameter(
                    "p", "%" + keyword + "%");

                ObjectQuery<ReferenceDescriptor> 
                     descriptorQuery = 
                     researchCollaborationData.
                     ReferenceDescriptor.Where(
                     "it.Annotation LIKE @p OR it.Keyword LIKE @p",
                     paramKeyword);

Each ReferenceDescriptor that is returned by the ObjectQuery enters a loop that loads the related Reference using its NavigationProperty and the Association designed for this purpose. The following code segment loads the Reference, reads its Locator property, and displays the URL to the Reference as a link in the results text box.

                           refDescriptor.ReferenceReference.Load();

                            Reference reference = refDescriptor.Reference;

                            textBoxAnnotationResults.Text = 
                                textBoxAnnotationResults.Text + "\n" +
                                reference.Locator + "\n";

Finally, the method finds and displays information about contacts related to the Reference. A static method of the LinkTable_Reference Association is used to locate the link table entities associated with the Reference. Instances of ContactPersonReference, the link table entities that contain the Reference, enter a loop that loads and displays properties of the related ContactPerson. The FirstName, LastName, Title, and Email properties are displayed paired with the Reference Annotation and Locator texts found by previous code.

                            foreach (ContactPersonReference contactPersRef in
                                researchCollaborationData.ContactPersonReference)
                            {
                                contactPersRef.RelatedReferenceReference.Load();
                                if (contactPersRef.RelatedReferenceReference.Equals(
                                    reference))
                                {
                                    contactPersRef.RelatedContactReference.Load();

                                    textBoxAnnotationResults.Text =
                                    textBoxAnnotationResults.Text +
                                    "\n" +
                                    "Relevant Contact:";

                                    textBoxAnnotationResults.Text =
                                        textBoxAnnotationResults.Text +
                                        "\n" +
                                        contactPersRef.
                                        RelatedContact.FirstName + " " +
                                        contactPersRef.RelatedContact.
                                        LastName +
                                        " Title: " + contactPersRef.
                                        RelatedContact.Title + " Email: "
                                        + contactPersRef.RelatedContact.
                                        Email
                                        + "\n";
                                }
                            }  

Find References associated with Contacts

Instances of Reference related to ContactPerson instances can be found by using the same link table entity and associations as the previous code segment. Users of this application can find reference pages from a contact by entering text in the LastName and/or Email textboxes and pushing the button labeled Find Ref/Person. New ObjectParameter instances are created from the LastName and Email texts. The parameters are used by an ObjectQuery to search for a person with matching last name or e-mail address. The Any method of the ObjectQuery is used to test whether there are any results from this query.

If an instance of ContactPerson with a matching last name or e-mail address is found, the contact information is displayed with associated Reference documents. The related documents are found, as in the previous method, by using the ContactPersonReference link entity and its navigation properties.

        private void buttonFindRefPerson_Click(object sender, EventArgs e)
        {
            ResearchCollaborationData researchCollaborationData = null;
            try
            {
                using (researchCollaborationData = 
                    new ResearchCollaborationData())
                {
                    // Use parameters from LastName and 
                    // Email text boxes in search.
                    ObjectParameter emailParam = new ObjectParameter(
                        "email", textBoxEmail.Text);
                    ObjectParameter nameParam = new ObjectParameter(
                        "name", textBoxLastName.Text);
                    ObjectParameter[] objParams = { emailParam, 
                        nameParam };
                    
                    ObjectQuery<ContactPerson> query = 
                        researchCollaborationData.ContactPerson.Where(
                        "it.Email = @email OR it.LastName = @name", 
                        objParams );

                    if (query.Any())
                    {
                        textBoxAnnotationResults.Text = 
                            "Contact and associated reference documents:\n";

                        ContactPerson person = null;
                        query.FirstOrDefault(out person);

                        // Display contact information and 
                        // related references.
                        textBoxAnnotationResults.Text = 
                            textBoxAnnotationResults.Text +
                            person.FirstName + " " + person.LastName +
                            " Title: " + person.Title +
                            " Email address: " + person.Email;

                        ObjectParameter contactParam = 
                            new ObjectParameter("p", 
                            person.ContactPersonID);

                        foreach (ContactPersonReference contactReference
                            in researchCollaborationData.
                            ContactPersonReference.Where(
                            "it.RelatedContact.ContactPersonID = @p",
                            contactParam))
                        {
                            contactReference.RelatedReferenceReference.
                                Load();

                            textBoxAnnotationResults.Text = 
                                textBoxAnnotationResults.Text + "\n" +
                                contactReference.RelatedReference.Locator;
                        }
                    }                                        
                }
            }

            catch (Exception exception)
            {
                MessageBox.Show(exception.ToString());
            }

        }

Complete Schemas and Application Code

The complete schemas and application code used by this example can be downloaded from the ADO.NET Entity Framework Documentation Samples resource page in MSDN Code Gallery. Requirements and instructions for building and running the sample are provided in the readme.htm file in the download package. A script is also provided with the downloadable project that can be used to create the database for this example.

See Also

Concepts

Annotation and Research Collaboration Tool (EDM Sample Application)
Annotation Research Tool Schemas (EDM Sample Application)