Código de HR Skills Application (aplicación de ejemplo de EDM)
El código que usa la aplicación HRSkills muestra varias características del Entity Data Model (EDM). Los esquemas descritos en los temas de HRSkills anteriores son la base para las entidades y las asociaciones que usa el código en esta sección. Para obtener más información acerca de las entidades y las asociaciones de este ejemplo, vea WinApp Human Resources Skills (aplicación de ejemplo de EDM). Para obtener más información acerca de los metadatos de almacenamiento, vea Metadatos de almacenamiento de HR Skills (aplicación de ejemplo de EDM). Para obtener la especificación de la asignación, vea Especificación de asignaciones de HR Skills (aplicación de ejemplo de EDM).
Los tipos diseñados en esquemas y asignados al almacenamiento se generan como un modelo de objetos programable. Los datos de este modelo se pueden programar con la sintaxis de Common Language Runtime (CLR) sin consultas SQL incrustadas como cadenas en el código.
La aplicación muestra el enlace de datos a las entidades, las consultas parametrizadas y el uso de propiedades de navegación a través de las asociaciones. Las asociaciones conectan los Employees con las References, los Employees con las Skills y las Skills con las entidades SkillInfo que contienen información sobre conocimientos.
Cadena de conexión y archivo de configuración
El uso del modelo de objetos requiere una conexión con la base de datos donde se almacenan los datos de la aplicación. También se necesita una conexión de entidad a los objetos de tiempo de ejecución que proporciona la DLL generada a partir de los esquemas. Para obtener más información acerca de cómo generar el modelo de objetos a partir de esquemas, vea Cómo Cómo usar EdmGen.exe para generar un modelo Entity Data Model (Entity Framework).
El archivo exe.config contiene una cadena de conexión que se utiliza para conectarse a una base de datos de SQL Server y establecer una conexión de entidad. Con una conexión de entidad, se puede obtener acceso a las entidades y asociaciones del modelo de objetos desde el código.
El programador debe agregar el texto de la cadena de conexión al archivo exe.config. Esta aplicación especifica la clase HRSkills
. La asignación providerName="System.Data.EntityClient"
especifica una conexión de entidad que utiliza el esquema de asignación definido en Especificación de asignaciones de HR Skills (aplicación de ejemplo de EDM).
La cadena de conexión también identifica el servidor que usa la conexión SQL: provider connection string="server=servername;
. provider connection string="server=servername;
.
En el ejemplo siguiente se muestra el contenido del archivo 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>
Código de la aplicación
El código siguiente contiene los controladores de eventos convencionales que se inicializan y ejecutan desde un formulario Windows Form que actúa como interfaz de usuario en esta aplicación de ejemplo. Las directivas using de preprocesador incluyen los espacios de nombres necesarios para ejecutar las consultas que permiten buscar empleados, referencias, conocimientos e información de los conocimientos. La directiva using final incluye el espacio de nombres HRSkillsModel
que contiene las clases de tiempo de ejecución para las entidades y relaciones del modelo de objetos definido y generado para esta aplicación, según se describe en los temas anteriores de esta sección.
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();
Se declara e inicializa una variable para el ObjectContext: HRSkills DB = new HRSkills
. ObjectContext contiene la conexión y la inicializa dentro de los corchetes try
, como se muestra en el segmento de código que sigue. Se puede leer cualquier mensaje de error de conexión mientras se prueba la aplicación.
La consulta inicial que se utiliza para mostrar todos los Employees en el almacenamiento utiliza la entidad Employees. La case Employees es una ObjectQuery<T> en el ObjectContext que devuelve todas las entidades de empleado.
Se usa un control DataGridView para mostrar los resultados de la consulta Employees. Las columnas se agregan a la DataGridView. El BindingSource se inicializa con la Consulta<T> de Employees y la propiedad DataSource del control enlaza los datos. Al usar el parámetro true, se actualiza la base de datos cuando se realizan modificaciones en el control 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());
}
}
Una vez mostrados los Employees en el control DataGridView, los usuarios de la aplicación pueden hacer clic en cualquier fila para obtener los Skills asociados a la entidad Employee que se muestra en esa fila. Una nueva consulta busca el EmployeeId de la entidad Employee cuyos datos se muestran en la DataGridView. El EmployeeId se oculta en la presentación de DataGridView pero se conserva como referencia. Lo utiliza una ObjectQuery<T> parametrizada en Employees. El parámetro se crea y se inicializa en la línea: ObjectParameter param = new ObjectParameter("p", empId)
. El ObjectParameter se usa en la consulta: DB.Employees.Where("it.EmployeeId = @p", param).First()
. DB.Employees.Where("it.EmployeeId = @p", param).First()
.
Una vez que la consulta identifica y devuelve la clase de empleado, la asociación Skill_Employee se utiliza para encontrar todos los Skills asociados a este empleado. Una línea de código utiliza la propiedad de navegación del empleado para cargar todos los Skills asociados al mismo desde la base de datos: Skill_Employee.GetSkillsEntities(employee).Load()
. Skill_Employee.GetSkillsEntities(employee).Load()
. A continuación, un bucle foreach en la misma propiedad de navegación lee los Skills asociados al empleado en un segundo control 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());
}
}
El método siguiente muestra la información sobre los Skills que contienen las entidades SkillInfo en un control RichTextBox en la interfaz de usuario. Las entidades SkillInfo asociadas a entidades Skills se consultan y muestran utilizando el mismo proceso que el método anterior. Una consulta toma SkillId como parámetro y busca una entidad Skills concreta. La propiedad de navegación de la entidad Skills se navega para encontrar todas las entidades SkillInfo asociadas al conocimiento.
Las propiedades de entidades SkillInfo contienen las direcciones URL que localizan información adicional sobre los Skills asociados. La dirección URL de cada entidad SkillInfo se muestra en el cuadro de texto enriquecido.
Se puede tener acceso a la entidad de empleado asociada a la entidad Skills que se usa en este método también desde la entidad Skills a través de la asociación Skill_Employee. Se carga una referencia al empleado desde la base de datos utilizando una línea de código: Skill_Employee.GetEmployeesRef(skill).Load()
. El empleado se asigna a una variable en una segunda línea: Employees employee = Skill_Employee.GetEmployees(skill)
. El alias del empleado se escribe en la presentación del cuadro de texto enriquecido.
Las referencias asociadas al empleado se obtienen de la asociación Reference_Employee. Las propiedades de las entidades References contienen el nombre, posición y dirección de correo electrónico de todas las referencias. Esta información se muestra en el Rich Text Box para complementar los vínculos a información sobre los conocimientos de los empleados.
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;
}
}
}
Esta aplicación le permite consultar Employees para determinar los conocimientos de los empleados o consultar Skills para determinar qué empleados tienen los conocimientos a los que se hace referencia en el sistema. El método que sigue toma los datos proporcionados por el usuario de un control TextBox y busca los empleados que tienen los conocimientos que describen dichos datos.
Esta consulta de Skills se inicia cuando el usuario escribe palabras clave, separadas por un espacio, en el control TextBox. Cuando se hace clic en el botón SkillSearch, se crea la lista de palabras clave a partir de la entrada del texto en el control TextBox de búsqueda.
Cada palabra clave de la lista se obtiene utilizando un bucle foreach. Un ObjectParameter se crea a partir de cada palabra clave: ObjectParameter param = new ObjectParameter("p", "%" + keyword + "%")
. Cada valor nuevo de la palabra clave para el parámetro se utiliza en una consulta nueva que busca en las propiedades BriefDescription y SkillName de todas las entidades Skills en el sistema: skillsQuery = DB.Skills.Where("it.BriefDescription Like @p OR it.SkillName Like @p", param)
. skillsQuery = DB.Skills.Where("it.BriefDescription Like @p OR it.SkillName Like @p", param)
.
Los resultados de la consulta son entidades Skills que tienen los nombres de los conocimientos o las descripciones que contienen una o varias de las palabras clave. Estos resultados se leen en la DataGridViewSkills. Se puede hacer clic en las filas de la presentación en la DataGridView a continuación para obtener información sobre los conocimientos y referencias del empleado. Al hacer clic en una fila de la DataGridViewSkills, se activa el controlador según se ha descrito anteriormente y las direcciones URL de SkillInfo, el Alias del empleado y las References se muestran en el control Rich Text Box de la UI.
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");
}
}
El controlador siguiente permite que los usuarios presionen <Entrar> en el TextBox que se usa para comenzar la búsqueda de palabras clave en lugar de hacer clic en el botón 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 );
}
El siguiente controlador se activa cuando el usuario envía la información que se usará para crear una nueva entidad Employees. El método valida primero la información de entrada; en este caso, sólo comprueba que la entrada de textBoxLastName y textBoxAlias contengan ambos texto. Una vez creada la nueva entidad Employees, el método comprueba si se trata de un duplicado de una entidad Employee que ya esté almacenada antes de agregar una entidad nueva al sistema.
Al crear la nueva entidad Employees, se requiere un nuevo Guid para la propiedad EmployeeId. Las propiedades LastName, FirstName, Email y Alias de la nueva entidad se asignan del contenido de los cuadros de texto en los que el usuario proporciona el texto.
Se necesitan dos llamadas a métodos para agregar una entidad al sistema. La primera agrega el nuevo objeto al contexto del objeto: DB.AddToEmployees(newEmployee)
. La nueva entidad no se guarda en la base de datos hasta la llamada al segundo método: 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");
}
}
Se activa el controlador siguiente cuando el usuario envía la información que se utilizará para crear una nueva entidad 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");
}
}
Se activa el controlador siguiente cuando el usuario envía la información que se utilizará para crear una nueva entidad 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");
}
}
Se activa el controlador siguiente cuando el usuario envía la información que se utilizará para crear una nueva entidad 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");
}
}
El controlador de eventos siguiente inicia el explorador de Internet para mostrar la dirección URL de SkillInfo que el método anterior escribe en el Rich Text Box.
private void richTextBox1_LinkClicked(object sender,
LinkClickedEventArgs e)
{
// Display the SkillInfo URL in Web browser.
System.Diagnostics.Process.Start(e.LinkText);
}
Se activa el controlador siguiente cuando el usuario hace doble clic en la etiqueta en el DataGridViewEmployees. Se usa para actualizar el DataGridViewEmployees cuando se agregan al sistema las nuevas entidades Employees. También se llama casi al final del controlador 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");
}
}
Vea también
Conceptos
WinApp Human Resources Skills (aplicación de ejemplo de EDM)
Metadatos de almacenamiento de HR Skills (aplicación de ejemplo de EDM)
Especificación de asignaciones de HR Skills (aplicación de ejemplo de EDM)