HR Skills アプリケーション コード (EDM サンプル アプリケーション)

HRSkills アプリケーションで使用されるコードは、エンティティ データ モデル (EDM) のいくつかの機能を示しています。前の HRSkills のトピックで説明したスキーマは、このセクションのコードで使用されるエンティティおよびアソシエーションの基礎となります。この例におけるエンティティおよびアソシエーションの詳細については、「Human Resources Skills WinApp (EDM サンプル アプリケーション)」を参照してください。ストレージ メタデータについては、「HR Skills ストレージ メタデータ (EDM サンプル アプリケーション)」を参照してください。マッピング スキーマについては「HR Skills マッピング スキーマ (EDM サンプル アプリケーション)」を参照してください。

スキーマで設計され、ストレージにマップされる型は、プログラミング可能なオブジェクト モデルとして構築されます。このモデルのデータは、コードに SQL クエリを文字列として組み込まずに、共通言語ランタイム (CLR) 構文を使用してプログラミングできます。

このアプリケーションは、エンティティへのデータ バインド、パラメータ化クエリ、およびアソシエーションでのナビゲーション プロパティの使用を示しています。アソシエーションによって、EmployeesReferences と接続され、EmployeesSkills と接続され、スキルに関する情報を含んでいる SkillInfo エンティティに Skills が接続されます。

構成ファイルと接続文字列

オブジェクト モデルを使用するには、アプリケーション データが保存されているデータベースへの接続が必要です。スキーマから構築された DLL で提供されているランタイム オブジェクトへのエンティティ接続も必要です。スキーマからオブジェクト モデルを構築する方法については、「EdmGen.exe を使用して Entity Data Model を生成する方法 (Entity Framework)」を参照してください。

exe.config ファイルには、SQL Server データベースに接続し、エンティティ接続を確立するために使用する接続文字列が含まれています。エンティティ接続を確立すると、オブジェクト モデル内のエンティティやアソシエーションにコードからアクセスできるようになります。

接続文字列のテキストは、開発者が exe.config ファイルに追加する必要があります。このアプリケーションは、HRSkills クラスを指定しています。providerName="System.Data.EntityClient" という割り当ては、HR Skills マッピング スキーマ (EDM サンプル アプリケーション) で定義されているマッピング スキーマを使用するエンティティ接続を指定します。

接続文字列では、SQL 接続 provider connection string="server=servername; によって使用されるサーバーも特定します。

次の例は、exe.config ファイルの内容を示しています。

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

アプリケーション コード

次のコードには、Windows フォームから初期化および実行される通常のイベント ハンドラが含まれており、このサンプル アプリケーションでユーザー インターフェイスとして使用できます。プリプロセッサ using ディレクティブには、従業員、参照、スキル、およびスキル情報を検索するクエリの実行に必要な名前空間が含まれています。最後の using ディレクティブには、このアプリケーション用に定義および構築されたオブジェクト モデル内のエンティティおよびリレーションシップのランタイム クラスを含む名前空間 HRSkillsModel が記述されています (このセクションの前の各トピックを参照)。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.Common;
using System.Data.Mapping;
using System.Data.Objects;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Data.Metadata;
using System.Linq;
using HRSkillsModel;

namespace HR_Skills_WinApp
{
    public partial class Form1 : Form
    {
        HRSkills DB = new HRSkills();
        
        public Form1()
        {
            InitializeComponent();

ObjectContext の変数は HRSkills DB = new HRSkills として宣言および初期化されています。次のコード セグメントに示されているように、接続は ObjectContext によって格納され、try のかっこ内で初期化されます。アプリケーションのテスト中に接続エラー メッセージがあれば読み取ることができます。

ストレージ内のすべての Employees を表示するために使用する最初のクエリでは、Employees エンティティを使用します。Employees クラスは、すべての従業員エンティティを返す ObjectContext 上の ObjectQuery<T> です。

DataGridView コントロールは、Employees クエリの結果を表示するために使用します。DataGridView には列が追加されます。BindingSourceEmployee の Query<T> に初期化され、コントロールの DataSource プロパティによってデータがバインドされます。パラメータ true を使用すると、DataGrid コントロールで編集が行われたときにデータベースが更新されます。

        public Form1()
        {
            InitializeComponent();

            try
            {
                bindingSource1.DataSource = DB.Employees;
                dataGridView1.DataSource = bindingSource1;
                dataGridView1.Columns[0].Visible = false;
            }
            catch(Exception e)
            {              
                System.Windows.Forms.MessageBox.Show(e.ToString());
            }
        }

EmployeesDataGridView コントロールに表示されたら、アプリケーション ユーザーは任意の行をクリックして、その行に表示された Employee エンティティと関連付けられている Skills を取得できます。新しいクエリにより、DataGridView にデータが表示されている Employee エンティティの EmployeeId が検出されます。EmployeeIdDataGridView には表示されませんが、参照用に保持されています。パラメータ化された ObjectQuery<T> により Employees で使用されます。パラメータは ObjectParameter param = new ObjectParameter("p", empId) 行で作成および初期化されます。ObjectParameter はクエリ DB.Employees.Where("it.EmployeeId = @p", param).First() で使用されます。

従業員クラスがクエリによって識別されて返されると、Skill_Employee アソシエーションを使用して、この従業員に関連付けられているすべての Skills が検出されます。1 行のコードで、従業員のナビゲーション プロパティを使用して、従業員に関連付けられているすべての Skills をデータベース Skill_Employee.GetSkillsEntities(employee).Load() から読み込みます。同じナビゲーション プロパティの foreach ループによって、従業員に関連付けられた Skills がもう 1 つの DataGridView コントロールに読み込まれます。

        private void dataGridView1_CellClick(object sender, 
            DataGridViewCellEventArgs e)
        {
            dataGridViewSkills.Columns.Clear();

            // Get the Id of the Employee and 
            Guid empId = new Guid(dataGridView1.CurrentRow.Cells[0].Value.ToString());

            // Find the Employee.
            ObjectParameter param = new ObjectParameter("p", empId);

            try
            {
                    if (null != DB.Employees.Where(
                        "it.EmployeeId = @p", param).First())
                    {

                        Employees employee = DB.Employees.Where(
                        "it.EmployeeId = @p", param).First();
                
                        employee.Skills.Load();
                        List<Skills> skillsList = new List<Skills>();
                        foreach (Skills skill in employee.Skills)
                        {
                            skillsList.Add(skill);
                        }

                        bindingSource2.DataSource = skillsList;
                        dataGridViewSkills.DataSource = bindingSource2;

                        dataGridViewSkills.Columns[0].Visible = false;
                        dataGridViewSkills.Columns[2].Width = 300;

                
                        richTextBox1.Clear();

                        // Provide EmployeeId for new skill or 
                        // reference association.
                        textBoxSkillEmployeeId.Text = 
                            employee.EmployeeId.ToString();

                        textBoxSkillEmployeeAlias.Text = employee.Alias;

                        textBoxRefEmployeeId.Text = 
                            employee.EmployeeId.ToString();

                        textBoxRefEmployeeAlias.Text = employee.Alias;
                    }

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.InnerException.ToString());
            }

        }

次のメソッドでは、ユーザー インターフェイスの RichTextBox コントロールの SkillInfo エンティティに含まれている Skills に関する情報が表示されます。Skills エンティティに関連付けられている SkillInfo エンティティは、前のメソッドと同じプロセスを使用して照会され、表示されます。クエリはパラメータとして SkillId を取り、特定の Skills エンティティを検索します。Skills エンティティのナビゲーション プロパティを参照して、スキルに関連付けられているすべての SkillInfo エンティティを検索します。

SkillInfo エンティティのプロパティには、関連する Skills についての追加情報の URL が含まれています。各 SkillInfo エンティティの URL がリッチ テキスト ボックスに表示されます。

このメソッドで使用される Skills エンティティに関連付けられた従業員エンティティは、Skill_Employee アソシエーションを使用して Skills エンティティからアクセスすることもできます。従業員への参照は、1 行のコード Skill_Employee.GetEmployeesRef(skill).Load() を使用してデータベースから読み込まれます。従業員は 2 行目 Employees employee = Skill_Employee.GetEmployees(skill) の変数に代入されます。従業員の別名はリッチ テキスト ボックス表示に書き込まれます。

従業員に関連付けられている参照は Reference_Employee アソシエーションから取得されます。すべての参照の名前、位置、および電子メール アドレスは References エンティティのプロパティに含まれています。この情報は Rich Text Box に表示されて従業員スキルに関する情報へのリンクを補完します。

        private void dataGridViewSkills_CellClick(object sender, 
            DataGridViewCellEventArgs e)
        {
            richTextBox1.Clear();
            // Write the name of the skill and brief 
            // description to richtext box.
            richTextBox1.Text = richTextBox1.Text + "Skill Name: "
                + dataGridViewSkills.CurrentRow.Cells[1].
                Value.ToString() + "\n" + 
                dataGridViewSkills.CurrentRow.Cells[2].
                Value.ToString();

            // Create ObjectParameter from the SkillId property 
            // and get the Skill.
            Guid skillId =
     new Guid(dataGridViewSkills.CurrentRow.Cells[0].Value.ToString());

            ObjectParameter param = 
                new ObjectParameter("p", skillId);

            Skills skill = DB.Skills.Where("it.SkillId = @p", 
                param).First();

            // Load the SkillInfo entities using 
            // SkillInfo_Skill association.
            skill.SkillInfo.Load();
            foreach (SkillInfo skillInfo in skill.SkillInfo)
            {
                richTextBox1.Text = richTextBox1.Text +
                    "\n\nSkill Information: " + skillInfo.URL + 
                    "\n";
            }

            dataGridView1.ClearSelection();

            // Load the Employee associated with the 
            // Skill using Skill_Employee association.
            skill.EmployeeReference.Load();
            Employees employee = skill.Employee;
            if (null == employee) return;

            // Write the alias property of the Employee to rich text 
            // box and heading for references.
            richTextBox1.Text = richTextBox1.Text + 
                "\n\nEmployee: " + employee.Alias + 
                "\n\n" + "References:";

            // Load References of Employee using 
            // Reference_Employee association.
            employee.References.Load();

            foreach (References reference in employee.References )
            {
                // Write reference LastName and Position to 
                // richtext box.
                richTextBox1.Text = richTextBox1.Text + "\n" +
                    reference.FirstName + " " + reference.LastName + 
                    "  Position: " + reference.Position + 
                    "  Email: " + reference.Email;
            }

            // Provide SkillId for new SkillInfo if needed.
            textBoxSkillInfoSkillId.Text = skill.SkillId.ToString();

            for (int i = 0; i < dataGridView1.RowCount; i++)
            {
                // Check to see if this is the employee associated
                // with the skill.
                if (dataGridView1.Rows[i].Cells[0].Value.ToString()
                    == employee.EmployeeId.ToString())
                {
                    dataGridView1.Rows[i].Selected = true;
                    dataGridView1.CurrentCell = dataGridView1[1, i];

                    // Break out when the row is found.
                    break;
                }

            }            
        }

このアプリケーションを使用すると、Employees を照会して従業員スキルを調べたり、Skills を照会してシステムで参照されているスキルを持つ従業員を調べたりできます。次のメソッドは、TextBox コントロールからユーザー入力を受け取り、ユーザー入力に記述されたスキルを持つ従業員を検索します。

Skills に関するこのクエリは、ユーザーが TextBox コントロールにキーワードをスペースで区切って入力すると開始されます。SkillSearch ボタンをクリックすると、検索 TextBox コントロールに入力したテキストからキーワードのリストが作成されます。

リスト内の各キーワードは foreach ループを使用して取得します。ObjectParameter は各キーワード ObjectParameter param = new ObjectParameter("p", "%" + keyword + "%") から作成されます。パラメータの新しいキーワード値は、システム内にあるすべての Skills エンティティの SkillName プロパティおよび BriefDescription プロパティを検索する新しいクエリで使用されます (skillsQuery = DB.Skills.Where("it.BriefDescription Like @p OR it.SkillName Like @p", param))。

クエリの結果は、スキル名または説明に 1 つまたは複数のキーワードが含まれている Skills エンティティです。これらの結果は SkillsDataGridView に読み込まれます。DataGridView の表示の行をクリックすると、スキルおよび従業員参照に関する情報を取得できます。SkillsDataGridView の行をクリックすると、前述のハンドラ、SkillInfo URL、従業員 Alias、および References が UI の Rich Text Box コントロールに表示されます。

        private void buttonSkillSearch_Click(object sender, EventArgs e)
        {
            dataGridViewSkills.DataSource = null;
            dataGridViewSkills.Columns.Clear();
            
            try
            {
                dataGridViewSkills.Columns.Add("idSkill", 
                    "Skill Id");
                dataGridViewSkills.Columns.Add("nameSkill", 
                    "Skill");
                dataGridViewSkills.Columns.Add("descSkill", 
                    "Description");
                dataGridViewSkills.Columns[2].Width = 300;

                // Make a list of keywords to search for in 
                // Skill entity name and description.
                List<string> keywords = new List<string>();
                int i = 0;
                int j = 0;

                while (i < textBoxKeywords.Text.Length)
                {
                    j = textBoxKeywords.Text.IndexOf(" ", i);
                    if (-1 == j) j = textBoxKeywords.Text.Length;
                    keywords.Add(
                        textBoxKeywords.Text.Substring(i, j - i));

                    i = ++j;
                }

                foreach (string keyword in keywords)
                {
                    // Create ObjectParameter from each keyword 
                    // and search properties of Skills.
                    ObjectParameter param = new ObjectParameter(
                        "p", "%" + keyword + "%");

                    ObjectQuery<Skills> skillsQuery = 
                        DB.Skills.Where(
                        "it.BriefDescription Like @p " +
                        "OR it.SkillName Like @p", param);

                    foreach (Skills skill in skillsQuery)
                    {
                        // Create an array of Skill property 
                        // strings for display.
                        string[] columnValues = 
                            new string[3] {skill.SkillId.ToString(),
                                skill.SkillName, 
                                skill.BriefDescription};

                        foreach (DataGridViewRow row in 
                            dataGridViewSkills.Rows)
                        {
                            // break if duplicate of 
                            // Skill already found.
                            if (row.Cells[0].Value != null)
                            {
                                if (row.Cells[0].Value.ToString()
                                    == columnValues[0])
                                {
                                    break;
                                }
                            }
                        }
                        dataGridViewSkills.Rows.Add(columnValues);
                    }
                }

                // Hide EmployeeId in datagrid, 
                // but keep for reference.
                dataGridViewSkills.Columns[0].Visible = false;

                richTextBox1.Clear();
            
            }

            catch(Exception ex)
            {
                System.Windows.Forms.MessageBox.Show(ex.ToString(),
                    "Error Message");
            }

        }

次のハンドラでは、Search ボタンをクリックする代わりに TextBox の <Enter> を押してキーワード検索を開始できます。

        private void textBoxKeywords_PreviewKeyDown(object sender, 
            PreviewKeyDownEventArgs e)
        {
            // Provide Enter activation in Search text box.
            if(e.KeyCode.Equals(Keys.Return))
                buttonSkillSearch_Click(this, System.EventArgs.Empty );
        }

ユーザーが新しい Employees エンティティを作成するときに使用する情報を送信すると、次のハンドラが呼び出されます。この場合、メソッドは最初に入力情報を検証し、textBoxLastNametextBoxAlias の両方の入力にテキストが含まれていることのみを確認します。新しい Employees エンティティが作成されると、メソッドはこのエンティティをシステムに追加する前に、既にストレージにある Employee エンティティと重複するかどうかを調べます。

新しい Employees エンティティを作成するには、EmployeeId プロパティの新しい Guid が必要になります。新しいエンティティの LastNameFirstNameAlias、および Email プロパティはテキスト ボックスのコンテンツから割り当てられ、テキストはユーザーが入力します。

エンティティをシステムに追加するには、2 つのメソッド呼び出しが必要です。1 つ目のメソッド呼び出し DB.AddToEmployees(newEmployee) では新しいオブジェクトがオブジェクト コンテキストに追加されます。2 つ目のメソッド呼び出し DB.SaveChanges() が実行されるまで、新しいエンティティはデータベースに保存されません。

        private void buttonSubmitEmployee_Click(object sender, 
            EventArgs e)
        {
            try
            {
                if ("".Equals(textBoxLastName.Text) || 
                    "".Equals(textBoxEmployeeAlias.Text))
                {
                    MessageBox.Show("Incomplete Information");
                    return;
                }

                // Create new Employee and add to storage.
                Employees newEmployee = new Employees();
                newEmployee.EmployeeId = Guid.NewGuid();
                newEmployee.LastName = textBoxLastName.Text;
                newEmployee.Alias = textBoxEmployeeAlias.Text;
                newEmployee.FirstName = textBoxFirstName.Text;
                newEmployee.Email = textBoxEmployeeEmail.Text;
                DB.AddToEmployees(newEmployee);

                // Check for duplicate.
                ObjectQuery<Employees> dbEmplQuery = 
                    DB.Employees.Where("it.Alias = @p", 
                    new ObjectParameter("p", newEmployee.Alias));

                if (!dbEmplQuery.Any())
                    DB.SaveChanges();

                //Refresh the Employees datagrid.
                EmployeesLabel_DoubleClick(this, null);

                textBoxFirstName.Clear();
                textBoxLastName.Clear();
                textBoxEmployeeAlias.Clear();
                textBoxEmployeeEmail.Clear();

            }
            catch (Exception ex)
            {
                System.Windows.Forms.MessageBox.Show(ex.ToString(), 
                    "Error Message");
            }
        }

ユーザーが新しい Skills エンティティを作成するときに使用する情報を送信すると、次のハンドラが呼び出されます。

        private void buttonSubmitSkill_Click(object sender, EventArgs e)
        {
            try
            {
                if ("".Equals(textBoxSkillShortName.Text) || 
                    "".Equals(textBoxSkillBriefDescription.Text) || 
                    "".Equals(textBoxSkillEmployeeId.Text))
                {
                    MessageBox.Show("Incomplete Information");
                    return;
                }

                // Create new Skills entity.
                Skills newSkills = new Skills();
                newSkills.SkillId = Guid.NewGuid();
                newSkills.SkillName = textBoxSkillShortName.Text; 
                newSkills.BriefDescription = 
                    textBoxSkillBriefDescription.Text;

                DB.AddToSkills(newSkills);

                // Make a Guid of EmployeeId of Employee who 
                // has this Skill and use it in query.
                Guid empId = 
                    new Guid(textBoxSkillEmployeeId.Text);
                ObjectParameter param = 
                    new ObjectParameter("p", empId);
                Employees employee = DB.Employees.Where(
                    "it.EmployeeId = @p", param).First();

                // Add the Skill to the Skill_Employee association.
                employee.Skills.Add(newSkills);

                DB.SaveChanges();
                textBoxSkillShortName.Clear();
                textBoxSkillBriefDescription.Clear();
                textBoxSkillEmployeeId.Clear();
                textBoxSkillEmployeeAlias.Clear();

            }

            catch (Exception ex)
            {
                System.Windows.Forms.MessageBox.Show(ex.ToString(),
                    "Error Message");
            }
        }

ユーザーが新しい SkillInfo エンティティを作成するときに使用する情報を送信すると、次のハンドラが呼び出されます。

        private void buttonSubmitSkillInfo_Click(object sender, 
            EventArgs e)
        {
            try
            {
                if ("".Equals(textBoxSkillInfoSkillId.Text) || 
                    "".Equals(textBoxUrlUncSkillInfo.Text))
                {
                    MessageBox.Show("Incomplete Information");
                    return;
                }

                // Create new SkillInfo entity.
                SkillInfo newSkillInfo = new SkillInfo();
                newSkillInfo.SkillInfoId = Guid.NewGuid();
                newSkillInfo.URL = textBoxUrlUncSkillInfo.Text;

                // Create query and find Skill to 
                // associate with SkillInfo.
                Guid empId = 
                    new Guid(textBoxSkillInfoSkillId.Text);
                ObjectParameter param = 
                    new ObjectParameter("p", empId);
                Skills skill = 
                    DB.Skills.Where("it.SkillId = @p",
                    param).First();

                // Add SkillInfo to SkillInfo_Skill association.
                skill.SkillInfo.Add(newSkillInfo);
                DB.AddToSkillInfo(newSkillInfo);
                DB.SaveChanges();

                textBoxSkillInfoSkillId.Clear();
                textBoxUrlUncSkillInfo.Clear();
            }

            catch (Exception ex)
            {
                System.Windows.Forms.MessageBox.Show(ex.ToString(), 
                    "Error Message");
            }

        }

ユーザーが新しい References エンティティを作成するときに使用する情報を送信すると、次のハンドラが呼び出されます。

        private void buttonSubmitReference_Click(
            object sender, EventArgs e)
        {
            try
            {
                if ("".Equals(textBoxRefEmployeeId.Text) || 
                    "".Equals(textBoxRefEmployeeAlias.Text))
                {
                    MessageBox.Show("Incomplete Information");
                    return;
                }

                // Create new Reference and add to 
                // Reference_Employee association.
                References reference = new References();
                reference.ReferenceId = Guid.NewGuid();
                reference.LastName = textBoxRefLastName.Text; 
                reference.Email = textBoxRefEmail.Text;
                reference.Alias = 
                    textBoxRefEmail.Text.Remove(
                    textBoxRefEmail.Text.IndexOf('@'));
                reference.FirstName = textBoxRefFirstName.Text;
                reference.Position = textBoxRefPosition.Text;

                Guid empId = new Guid(
                    dataGridView1.CurrentRow.Cells[0].
                    Value.ToString());
                ObjectParameter param = new ObjectParameter(
                    "p", empId);
                Employees employee = DB.Employees.Where(
                    "it.EmployeeId = @p", param).First();

                DB.AddToReferences(reference);
                employee.References.Add(reference);

                DB.SaveChanges();

                textBoxRefFirstName.Clear();
                textBoxRefLastName.Clear();
                textBoxRefEmail.Clear();
                textBoxRefPosition.Clear();

            }
            catch (Exception ex)
            {
                System.Windows.Forms.MessageBox.Show(ex.ToString(), 
                    "Error Message");
            }

        }

次のイベント ハンドラはインターネット ブラウザを起動して、前のメソッドによって Rich Text Box に書き込まれた SkillInfo URL を表示します。

        private void richTextBox1_LinkClicked(object sender,
                                             LinkClickedEventArgs e)
        {  
            // Display the SkillInfo URL in Web browser.
            System.Diagnostics.Process.Start(e.LinkText);
        }

EmployeesDataGridView のラベルをダブルクリックすると、次のハンドラが呼び出されます。新しい Employees エンティティがシステムに追加されたときに、ハンドラを使用して EmployeesDataGridView を更新します。buttonSubmitEmployee_Click ハンドラの終了間際にも呼び出されます。

        private void EmployeesLabel_DoubleClick(object sender, 
            EventArgs e)
        {
            try
            {
                DB.Dispose();   //Dispose to refresh the data.
                DB = new HRSkills();
                bindingSource1.DataSource = DB.Employees;
                dataGridView1.DataSource = bindingSource1;
                dataGridView1.Columns[0].Visible = false;

            }
            catch (Exception ex)
            {
                System.Windows.Forms.MessageBox.Show(ex.ToString(), 
                    "Error Message");
            }
        }

参照

概念

Human Resources Skills WinApp (EDM サンプル アプリケーション)
HR Skills ストレージ メタデータ (EDM サンプル アプリケーション)
HR Skills マッピング スキーマ (EDM サンプル アプリケーション)