共用方式為


人力資源應用程式程式碼 (EDM 範例應用程式)

HRSkills 應用程式使用的程式碼會示範 實體資料模型 (EDM) 的幾項功能。之前 HRSkills 主題中所述的結構描述是本章節程式碼所使用之實體和關聯的基礎。如需本範例中實體和關聯的詳細資訊,請參閱人力資源技能 WinApp (EDM 範例應用程式)。如需儲存中繼資料的詳細資訊,請參閱人力資源儲存中繼資料 (EDM 範例應用程式)。如需對應規格,請參閱人力資源技能對應規格 (EDM 範例應用程式)

在結構描述中設計且對應到儲存區的型別會建置為可程式化物件模型。可以使用 Common Language Runtime (CLR) 語法來針對此模型上的資料進行程式設計,而不需要將 SQL 查詢當做字串內嵌在程式碼中。

此應用程式會示範與實體之間的資料繫結、參數化查詢及透過關聯使用導覽屬性。關聯會將 Employees 連接到 References、將 Employees 連接到 Skills,並將 Skills 連接到包含相關技能資訊的 SkillInfo 實體。

組態檔和連接字串

使用此物件模型需要連接到儲存應用程式資料的資料庫。此外,也需要讓實體連接到從結構描述建置之 DLL 所提供的執行階段物件。如需從結構描述建置物件模型的詳細資訊,請參閱 HOW TO:HOW TO:使用 EdmGen.exe 產生 Entity Data Model (Entity Framework)

exe.config 檔案包含一個連接字串,此字串是用來連接 SQL Server 資料庫及建立實體連接。當實體連接準備好時,可以從程式碼存取物件模型中的實體和關聯。

此連接字串必須由開發人員加入到 exe.config 檔。這個應用程式會指定 HRSkills 類別。providerName="System.Data.EntityClient" 指派會指定一個實體連接,該連接使用了人力資源技能對應規格 (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 Form 初始化及執行的傳統事件處理常式,此 Windows Form 會當做這個範例應用程式中的使用者介面。前置處理器指示詞 (Preprocessing Directive) 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 查詢的結果。資料行會加入到 DataGridViewBindingSource 會初始化成 Employee 的查詢<T>,而控制項的 DataSource 屬性會繫結資料。在 DataGrid 控制項內進行編輯時,使用 true 參數會更新資料庫。

        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());
            }
        }

DataGridView 控制項內顯示 Employees 之後,應用程式使用者可按一下任何資料列,以取得與該資料列中顯示之 Employee 實體有關的 Skills。新的查詢會尋找在 DataGridView 中顯示資料之 Employee 實體的 EmployeeIdDataGridView 顯示中會隱藏 EmployeeId,但是會將它保留起來以供參考。它是由 Employees 上的參數化 ObjectQuery<T> 所使用。此參數是在這一行建立及初始化:ObjectParameter param = new ObjectParameter("p", empId)ObjectParameter 會用於以下查詢:DB.Employees.Where("it.EmployeeId = @p", param).First()

當查詢已經識別及傳回員工類別之後,Skill_Employee 關聯會用來尋找與這名員工有關的所有 Skills。其中一行程式碼會使用此員工的導覽屬性,從資料庫載入與此員工有關的所有 SkillsSkill_Employee.GetSkillsEntities(employee).Load()foreach 會在相同的導覽屬性上循環,然後將與此員工有關的 Skills 讀入第二個 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());
            }

        }

下一個方法會顯示有關 Skills 的資訊,它是由使用者介面上 RichTextBox 控制項內的 SkillInfo 實體所容納。與 Skills 實體有關的 SkillInfo 實體會使用與前一個方法相同的程序來查詢及顯示。查詢會使用 SkillId 當做參數,並尋找特定的 Skills 實體。導覽 Skills 實體的導覽屬性來尋找與此技能有關的所有 SkillInfo 實體。

SkillInfo 實體的屬性包含了可尋找與關聯之 Skills 相關之其他資訊的 URL。每一個 SkillInfo 實體中的 URL 都會顯示在 Rich Text 格式方塊中。

與這個方法中使用之 Skills 實體有關的員工實體也可以透過 Skill_Employee 關聯從 Skills 實體加以存取。使用下列這一行程式碼,從資料庫載入此員工的參考:Skill_Employee.GetEmployeesRef(skill).Load()。此員工會指派給第二行的變數:Employees employee = Skill_Employee.GetEmployees(skill)。此員工的別名會寫入 Rich Text 格式方塊的顯示中。

與此員工有關的參考是從 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 控制項中的使用者輸入,並搜尋具有使用者輸入所描述之技能的員工。

當使用者在 TextBox 控制項中輸入關鍵字 (以空格分隔) 時,就會啟始 Skills 上的這個查詢。按一下 SkillSearch 按鈕時,會從搜尋 TextBox 控制項文字的輸入建立關鍵字的清單。

清單中的每一個關鍵字都是使用 foreach 迴圈所取得。ObjectParameter 是從每一個關鍵字建立而來:ObjectParameter param = new ObjectParameter("p", "%" + keyword + "%")。此參數的每一個新關鍵字值都會用於新的查詢中,該查詢會搜尋系統中所有 Skills 實體的 SkillNameBriefDescription 屬性:skillsQuery = DB.Skills.Where("it.BriefDescription Like @p OR it.SkillName Like @p", param)

此查詢的結果為 Skills 實體,這些實體的技能名稱或描述包含一或多個關鍵字。這些結果會讀入 SkillsDataGridView。然後可以按一下 DataGridView 中顯示的資料列,以取得有關技能和員工參考的資訊。在 SkillsDataGridView 中按一下資料列時,會佔用處理常式 (如之前所述),而且 UI 上的 Rich Text Box 控制項會顯示 SkillInfo URL、員工 AliasReferences

        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");
            }

        }

下列處理常式會讓使用者在用來開始關鍵字搜尋的 TextBox 中按下 <Enter>,而不是按一下 Search 按鈕。

        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。從使用者提供文字的文字方塊內容指派新實體的 LastNameFirstNameAliasEmail 屬性。

將實體加入系統時,需要兩個方法呼叫。第一個會將新的物件加入到物件內容:DB.AddToEmployees(newEmployee)。要等到呼叫第二個方法之後,才會將新的實體儲存到資料庫: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 BoxSkillInfo 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");
            }
        }

另請參閱

概念

人力資源技能 WinApp (EDM 範例應用程式)
人力資源儲存中繼資料 (EDM 範例應用程式)
人力資源技能對應規格 (EDM 範例應用程式)