HR Skills 응용 프로그램 코드(EDM 샘플 응용 프로그램)
HRSkills 응용 프로그램에 사용된 코드는 EDM(엔터티 데이터 모델)의 몇 가지 기능을 보여 줍니다. 이전 HRSkills 항목에 설명된 스키마가 이 단원의 코드에서 사용하는 엔터티 및 연결의 기본 스키마가 됩니다. 이 예제의 엔터티 및 연결에 대한 자세한 내용은 Human Resources Skills WinApp(EDM 샘플 응용 프로그램)를 참조하십시오. 저장소 메타데이터에 대한 자세한 내용은 HR Skills 저장소 메타데이터(EDM 샘플 응용 프로그램)를 참조하십시오. 매핑 사양에 대한 자세한 내용은 HR Skills 매핑 사양(EDM 샘플 응용 프로그램)을 참조하십시오.
스키마에서 디자인되고 저장소에 매핑된 형식은 프로그래밍 가능한 개체 모델로 구성됩니다. 이 모델의 데이터는 코드에 문자열로 포함되는 SQL 쿼리 없이 CLR(공용 언어 런타임) 구문을 사용하여 프로그래밍 가능합니다.
이 응용 프로그램은 엔터티에 대한 데이터 바인딩, 매개 변수가 있는 쿼리 및 연결에 대한 탐색 속성 사용을 보여 줍니다. 연결에서는 Employees를 References와 연결하고, Employees를 Skills와 연결하며, Skills를 기술 정보가 들어 있는 SkillInfo 엔터티와 연결합니다.
구성 파일 및 연결 문자열
개체 모델을 사용하려면 응용 프로그램 데이터가 저장된 데이터베이스에 연결해야 합니다. 스키마로 빌드한 DLL에서 제공하는 런타임 개체에 대한 엔터티 연결도 필요합니다. 스키마에서 개체 모델을 작성하는 방법에 대한 자세한 내용은 방법: 방법: EdmGen.exe를 사용하여 엔터티 데이터 모델 생성(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 Form에서 초기화되고 실행되는 일반적인 이벤트 처리기가 들어 있습니다. 전처리기 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>**입니다.
Employees 쿼리 결과를 표시하기 위해 DataGridView 컨트롤을 사용합니다. 열을 DataGridView에 추가합니다. BindingSource는 Employees의 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());
}
}
DataGridView 컨트롤에 Employees가 표시되면 응용 프로그램 사용자는 임의의 행을 클릭하여 해당 행에 표시된 Employee 엔터티와 관련된 Skills를 가져올 수 있습니다. 새 쿼리에서는 해당 데이터가 DataGridView에 표시된 Employee 엔터티의 EmployeeId를 찾습니다. EmployeeId는 DataGridView 표시에서 숨겨지지만 참조를 위해 유지되며, Employees에서 매개 변수가 있는 **ObjectQuery<T>**에 의해 사용됩니다. 매개 변수는 다음 줄에서 만들어지고 초기화됩니다. ObjectParameter param = new ObjectParameter("p", empId)
. 다음 쿼리에서 ObjectParameter가 사용됩니다. DB.Employees.Where("it.EmployeeId = @p", param).First()
.
쿼리에서 employee 클래스가 식별되어 반환되면 Skill_Employee 연결을 사용하여 이 직원과 관련된 모든 Skills를 찾습니다. 다음 코드 줄에서는 직원의 탐색 속성을 사용하여 데이터베이스에서 직원과 관련된 모든 Skills를 로드합니다. Skill_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());
}
}
다음 메서드에서는 SkillInfo 엔터티에 포함된 Skills에 대한 정보를 사용자 인터페이스의 RichTextBox 컨트롤에 표시합니다. Skills 엔터티와 관련된 SkillInfo 엔터티는 이전 메서드와 동일한 프로세스를 사용하여 쿼리되고 표시됩니다. 쿼리는 SkillId를 매개 변수로 사용하여 특정 Skills 엔터티를 찾습니다. 기술과 관련된 모든 SkillInfo 엔터티를 찾기 위해 Skills 엔터티의 탐색 속성을 탐색합니다.
SkillInfo 엔터티의 속성에는 관련된 Skills의 추가 정보에 대한 URL이 들어 있습니다. 각 SkillInfo 엔터티의 URL은 RTF 상자에 표시됩니다.
이 메서드에 사용된 Skills 엔터티와 관련된 직원 엔터티는 Skill_Employee 연결을 통해 Skills 엔터티에서 액세스할 수도 있습니다. 다음 코드 줄을 사용하여 데이터베이스에서 직원에 대한 참조를 로드합니다. 두 번째 줄에서 직원이 변수에 할당됩니다. 직원 별칭은 RTF 상자 표시에 작성됩니다.
직원과 관련된 참조는 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 엔터티에 대한 SkillName 및 BriefDescription 속성을 검색하는 새 쿼리에서 사용됩니다. skillsQuery = DB.Skills.Where("it.BriefDescription Like @p OR it.SkillName Like @p", param)
.
쿼리 결과는 하나 이상의 키워드가 포함된 기술 이름 또는 설명이 들어 있는 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 엔터티를 새로 만드는 데 사용될 정보를 사용자가 제출하면 다음 처리기가 실행됩니다. 메서드는 먼저 입력 정보의 유효성을 검사하며, 이 경우 textBoxLastName 및 textBoxAlias의 모든 입력에 텍스트가 포함되었는지만 확인합니다. 새 Employees 엔터티가 생성되면 메서드는 새 엔터티를 시스템에 추가하기 전에 중복된 Employee 엔터티가 이미 저장소에 있는지 확인합니다.
새 Employees 엔터티를 생성하려면 EmployeeId 속성에 대한 새 Guid가 필요합니다. 새 엔터티의 LastName, FirstName, Alias 및 Email 속성은 사용자가 텍스트를 제공한 텍스트 상자의 내용에서 할당됩니다.
엔터티를 시스템에 추가하려면 두 개의 메서드를 호출해야 합니다. 첫 번째 메서드에서 새 개체를 개체 컨텍스트에 추가합니다. 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 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 샘플 응용 프로그램)