Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Question
Friday, July 28, 2017 5:22 PM
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public interface IPerson
{
int Insert(Person person);
int update(Person person);
int delete(int personId);
}
//Data Access Layer
public class PersonRepository:IPerson
{
public int Insert(Person person)
{
//sql code here
}
public int update(Person person)
{
//sql code here
}
public int delete(int personId)
{
//sql code here
}
}
//Business Layer
public class PersonBLL:IPerson
{
PersonRepository personRepository=new PersonRepository();
public int Insert(Person person)
{
return personRepository.Insert(person);
}
public int update(Person person)
{
return personRepository.update(person);
}
public int delete(int personId)
{
return personRepository.delete(personId);
}
}
This code was derived from the Data Access Object Pattern, i just added a business layer that acts as a wrapper so that the UI layer don't need to call the data layer directly. Now, i'm pretty confuse if i'm using or do i need the interface at all because all it does it to make sure that all the methods will be implemented.
By the way im using Dapper to map my sql results to objects.
Regards
All replies (5)
Friday, July 28, 2017 5:38 PM âś…Answered
The issue with your code is that you're defining an interface for an entity, not the repo. It is the repo that needs the interface. The entity can be used as is.
//No changes, use this type directly in your code
public class Person { }
//Repo
public interface IPersonRepository
{
int Insert ( Person person );
int Update ( Person person );
int Delete ( int personId );
}
//Repo impl using ADO.NET
public class AdoNetPersonRepository : IPersonRepository
{
public int Insert ( Person person )
{ /* SQL goes here */ }
public int Update ( Person person )
{ /* SQL goes here */ }
public int Delete ( int personId )
{ /* SQL goes here */ }
}
//Alternative version using EF
public class EFPersonRepository : IPersonRepository
{
public int Insert ( Person person )
{ /* EF goes here */ }
public int Update ( Person person )
{ /* EF goes here */ }
public int Delete ( int personId )
{ /* EF goes here */ }
}
//App gets to decide which version to use
var repo = CreateRepository();
IPersonRepository CreateRepository ()
{
//Normally this is done using DI containers but
//to keep it simple we'll choose AdoNet today
return new AdoNetPersonRepository();
}
Of course your repo is probably one of several so the actual type you'd create is probably the higher level DB context/Unit of Work/Session that exposes the repo interfaces. The higher level object determines the repo impls to return (most likely they are hidden inside its code). Given this type of architecture you can switch from ADO.NET to EF to Dapper to whatever else you want and, in theory, your app doesn't change other than the one little new statement.
Michael Taylor
http://www.michaeltaylorp3.net
Friday, July 28, 2017 5:49 PM
Thanks for the quick reply.
So the use of the interface is when i need to switch to different architecture? I switched to Dapper because it makes mapping the results to object so easy and at the moment i am very much happy with it and i don't like to use EF either. Maybe i can remove those interfaces :D
I now fully understand the use of it. I never thought i can switch between Dapper and EF.
Cheers
Friday, July 28, 2017 6:47 PM
"So the use of the interface is when i need to switch to different architecture"
That is one usage but if that is all you think interfaces are for then you've sort of missed the point of an interface. An interface is a contract between 2 different pieces of code that allows them to communicate without regard for how the other side is implemented.
It is important to understand why interfaces are useful in your code and why, in general, development has moved to contract-based programming.
Interfaces hide implementation details. Imagine for a second what it takes to implement your Insert method. Given the signature you are accepting an object and returning an ID. I assume this is probably the primary key. To get that key you actually have to insert the data and then commit it. In most systems this is a 2 step process. If you removed the interface and simply put this code into each place you need to insert an item then your code is riddled with the implementation details. One day when a new function is added to your ORM that allows you to do this in 1 line of code you have to update all your existing code to use it. Maintenance becomes an issue and you have to retest all the places you changed.
Testing is another very big benefit of interfaces. I assume you intend to unit test your code. How are you going to test the code that interacts with your data layer? If your intent is to point your tests to a test database then you're no longer writing unit tests but integration tests. Unit tests, by definition, should be repeatable and runnable in any order. If they rely on a shared source then they violate this rule. You could spin up a new source for each test but performance is going to be bad. Normally we will mock the data layer. For unit testing you're not testing the data layer but your code's interaction with it. You are, correctly so, assuming the data layer will do exactly what it says it will (and however it is supposed to). You cannot mock non-interfaces easily.
Finally, you're confidence in using the same ORM forever is encouraging but in my experience unrealistic. Nothing is forever. Imagine 5 years from now that Dapper has been deprecated in lieu of Dupper which takes advantages of the newer technologies without the legacy baggage. How are you going to update your app? If you're using an interface then, in theory, you can write a new impl of the interface against Dupper and then do integration testing. This makes it dramatically easier to maintain your code. To be fair such a change likely would require more changes to your app outside the interface but that is a sign of an "incorrect" interface design rather than an issue with interfaces.
So you could remove the interface if you only intend to use 1 ORM, and there may be benefits in doing so. But personally I find the best architectures always use interfaces between layers and components. Skip the interfaces for implementation details inside layers (except for testing) but use interfaces most everywhere else.
Friday, July 28, 2017 6:57 PM
Thanks for the quick reply.
So the use of the interface is when i need to switch to different architecture? I switched to Dapper because it makes mapping the results to object so easy and at the moment i am very much happy with it and i don't like to use EF either. Maybe i can remove those interfaces :D
I now fully understand the use of it. I never thought i can switch between Dapper and EF.
Cheers
The use of the Interface is to establish a contract between the called and calling objects, as to what properties and or methods are exposed publicly on the called object that the calling object has access to.
I use EF with the DAO pattern in the DAL with the Repository calling DAO objects in the DAL for CRUD
The key is the DTO which is an abstraction away from the underling DB technology. The underlying DB technology can change, but any layers above the DAL are not affected because of the DTO.
htthttps://docs.microsoft.com/en-us/aspnet/web-api/overview/data/using-web-api-with-
https://en.wikipedia.org/wiki/Data_transfer_object
/en-us/aspnet/web-api/overview/data/using-web-api-with-entity-framework/part-5
Example.......
using System;
using System.Collections.Generic;
using Entities;
namespace Repository
{
public interface IStudentRepo
{
DTOStudent GetStudentById(Int32 id);
List<DTOStudent> GetStudents();
void CreateStudent(DTOStudent dto);
void UpdateStudent(DTOStudent dto);
void DeleteStudent(Int32 id);
}
}
using System.Collections.Generic;
using Entities;
using DAL.DAO;
namespace Repository
{ public class StudentRepo : IStudentRepo
{
private IDAOStudent dao;
public StudentRepo(IDAOStudent doaStudent)
{
dao = doaStudent;
}
public DTOStudent GetStudentById(int id)
{
return dao.GetStudentById(id);
}
public List<DTOStudent> GetStudents()
{
return dao.GetStudents();
}
public void CreateStudent(DTOStudent dto)
{
dao.CreateStudent(dto);
}
public void UpdateStudent(DTOStudent dto)
{
dao.UpdateStudent(dto);
}
public void DeleteStudent(int id)
{
dao.DeleteStudent(id);
}
}
}
using System;
using System.Collections.Generic;
using Entities;
namespace DAL.DAO
{
public interface IDAOStudent
{
DTOStudent GetStudentById(Int32 id);
List<DTOStudent> GetStudents();
void CreateStudent(DTOStudent dto);
void UpdateStudent(DTOStudent dto);
void DeleteStudent(Int32 id);
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Data.Entity;
using Entities;
using DAL.Model;
namespace DAL.DAO
{
public class DAOStudent : IDAOStudent
{
public DTOStudent GetStudentById(Int32 id)
{
var dto = new DTOStudent();
using (var context = new CUDataEntities())
{
var student = (context.Students.Where(a => a.StudentID == id)).SingleOrDefault();
if (student != null)
{
dto.StudentID = student.StudentID;
dto.FirstName = student.FirstName;
dto.LastName = student.LastName;
dto.EnrollmentDate = student.EnrollmentDate;
var enrolllments = new DAOEnrollment().GetEntrollmentsByStudentId(id).ToList();
var courses = new DAOCourse().GetCoursesByStudentCourseId(student.StudentID).ToList();
dto.EnrollsandCourses = (from a in enrolllments
join b in courses on a.CourseID equals b.CourseID
select new DTOEnrollandCourse()
{ Title = b.Title, Credits = b.Credits, Grade = a.Grade }).ToList();
}
}
return dto;
}
public void CreateStudent(DTOStudent dto)
{
using (var context = new CUDataEntities())
{
var student = new Student
{
FirstName = dto.FirstName,
LastName = dto.LastName,
EnrollmentDate = dto.EnrollmentDate
};
context.Students.Add(student);
context.SaveChanges();
}
}
public void DeleteStudent(int id)
{
Student student;
using (var context = new CUDataEntities())
{
student = (context.Students.Where(a => a.StudentID == id)).SingleOrDefault();
}
using (var newContext = new CUDataEntities())
{
newContext.Entry(student).State = System.Data.Entity.EntityState.Deleted;
newContext.SaveChanges();
}
}
public List<DTOStudent> GetStudents()
{
var dtos = new List<DTOStudent>();
using (var context = new CUDataEntities())
{
var students = context.Students.ToList();
foreach(var stud in students)
{
var dto = new DTOStudent
{
StudentID = stud.StudentID,
FirstName = stud.FirstName,
LastName = stud.LastName,
EnrollmentDate = stud.EnrollmentDate
};
dtos.Add(dto);
}
}
return dtos;
}
public void UpdateStudent(DTOStudent dto)
{
var student = new Student();
using (var context = new CUDataEntities())
{
student = (context.Students.Where(a => a.StudentID == dto.StudentID)).SingleOrDefault();
}
if (student != null)
{
student.FirstName = dto.FirstName;
student.LastName = dto.LastName;
student.EnrollmentDate = dto.EnrollmentDate;
}
using (var dbcontext = new CUDataEntities())
{
if (student != null)
{
dbcontext.Entry(student).State = EntityState.Modified;
dbcontext.SaveChanges();
}
}
}
}
}
Friday, February 15, 2019 2:50 PM
///****************************Form Est
List<Estudiante> estudiantes = new List<Estudiante>();
private List<Matricula> listaMatriculas1=new List<Matricula>();
public FrmEstudiante()
{
InitializeComponent();
}
public FrmEstudiante(List<Matricula> listaMatriculas1)
{
this.listaMatriculas1 = listaMatriculas1;
InitializeComponent();
}
private void cargarListaVisual()
{
lstEstudiantes.Items.Clear();
estudiantes = EstudianteDAO.obtenerEstudiantes();
foreach (var iter in estudiantes)
{
lstEstudiantes.Items.Add(iter);
}
}
private void lstEstudiantes_SelectedIndexChanged(object sender, EventArgs e)
{
}
private void FrmEstudiante_Load(object sender, EventArgs e)
{
cargarListaVisual();
}
private void btnSiguiente_Click(object sender, EventArgs e)
{
Estudiante est=(Estudiante)lstEstudiantes.SelectedItem;
int numMaxCreditos = Convert.ToInt32(txtMaxCreditos.Text);
FrmNuevaMatricula frmNuevaMatricula = new FrmNuevaMatricula(est,numMaxCreditos,listaMatriculas1);
frmNuevaMatricula.Show();
// this.Hide();
}
///***********************************Form nueva
private Estudiante est;
private int numMaxCreditos;
public List<Categoria> categorias = new List<Categoria>();
public List<Asignatura> asignaturas = new List<Asignatura>();
public List<Asignatura> ListaAsignSelec = new List<Asignatura>();
public Asignatura asigSeleccionada;
private List<Matricula> listaMatriculas1=new List<Matricula>();
public FrmNuevaMatricula()
{
InitializeComponent();
}
// public FrmNuevaMatricula(Estudiante est, int numMaxCreditos)
// {
// this.est = est;
// this.numMaxCreditos = numMaxCreditos;
// InitializeComponent();
// }
public FrmNuevaMatricula(Estudiante est, int numMaxCreditos, List<Matricula> listaMatriculas1)
{
this.est = est;
this.numMaxCreditos = numMaxCreditos;
this.listaMatriculas1 = listaMatriculas1;
InitializeComponent();
}
private void FrmNuevaMatricula_Load(object sender, EventArgs e)
{
cbxTipoAsignatura.Items.Clear();
categorias = CategoriaDAO.obtenerCategoria();
foreach (var item in categorias)
{
cbxTipoAsignatura.Items.Add(item);
}
}
private void cbxTipoAsignatura_SelectedIndexChanged(object sender, EventArgs e)
{
List<Asignatura>asig= AsignaturasDAO.obtenerAsignaturas((Categoria)cbxTipoAsignatura.SelectedItem);
lstAsignaturas.Items.Clear();
foreach (var item in asig)
{
lstAsignaturas.Items.Add(item);
}
}
private void btnAgregar_Click(object sender, EventArgs e)
{
asigSeleccionada = (Asignatura)lstAsignaturas.SelectedItem;
if (numMaxCreditos>=asigSeleccionada.NumCreditos)
{
ListaAsignSelec.Add(asigSeleccionada);
lstAsignaturasSeleccionadas.Items.Clear();
foreach (var item in ListaAsignSelec)
{
lstAsignaturasSeleccionadas.Items.Add(item);
}
numMaxCreditos = numMaxCreditos - asigSeleccionada.NumCreditos;
}
else
{
MessageBox.Show("Numero de creditos insuficiente");
}
}
private void btnEliminar_Click(object sender, EventArgs e)
{
Asignatura aux=(Asignatura) lstAsignaturasSeleccionadas.SelectedItem;
ListaAsignSelec.Remove(aux);
lstAsignaturasSeleccionadas.Items.Clear();
foreach (var item in ListaAsignSelec)
{
lstAsignaturasSeleccionadas.Items.Add(item);
}
}
private void btnSiguiente_Click(object sender, EventArgs e)
{
FrmResumen frmResumen = new FrmResumen(est,numMaxCreditos,ListaAsignSelec,listaMatriculas1);
frmResumen.Show();
//this.Hide();
}
///**************************form resu
private Estudiante est;
private int numMaxCreditos;
private List<Asignatura> listaAsignSelec=new List<Asignatura>();
private List<Matricula> listaMatriculas1=new List<Matricula>();
public FrmResumen(Estudiante est)
{
InitializeComponent();
}
public FrmResumen(Estudiante est, int numMaxCreditos, List<Asignatura> listaAsignSelec, List<Matricula> listaMatriculas1)
{
this.listaMatriculas1 = listaMatriculas1;
this.est = est;
this.numMaxCreditos = numMaxCreditos;
this.listaAsignSelec = listaAsignSelec;
InitializeComponent();
}
private void FrmResumen_Load(object sender, EventArgs e)
{
txtIdMatricula.Text =Convert.ToString(listaMatriculas1.Count()+1);
lstMaterias.Items.Clear();
foreach (var item in listaAsignSelec)
{
lstMaterias.Items.Add(item);
}
txtEstudiante.Text = est.NombreEstudiante;
}
public Matricula Ma = new Matricula();
private void btnFinalizar_Click(object sender, EventArgs e)
{
Ma.Estudiante = new Estudiante();
Ma.Asignaturas=new List<Asignatura>();
foreach (var item in listaAsignSelec)
{
Ma.Asignaturas.Add(item);
}
Ma.Estudiante = est;
Ma.IdMatricula = listaMatriculas1.Count() + 1;
listaMatriculas1.Add(Ma);
MessageBox.Show("maatricula ngresada con exito");
Form1 form1 = new Form1();
form1.ShowDialog();
this.Close();
///************************form mt
private List<Matricula> listaMatriculas1;
public FrmMatriculas()
{
InitializeComponent();
}
public FrmMatriculas(List<Matricula> listaMatriculas1)
{
this.listaMatriculas1 = listaMatriculas1;
InitializeComponent();
}
Matricula aux=new Matricula();
private void FrmMatriculas_Load(object sender, EventArgs e)
{
foreach (var item in listaMatriculas1)
{
lstMatriculas.Items.Add(item);
//aux = item;
}
}
private void lstMatriculas_SelectedIndexChanged(object sender, EventArgs e)
{
aux =(Matricula) lstMatriculas.SelectedItem;
// aux.Asignaturas = new List<Asignatura>();
lstMaterias.Items.Clear();
foreach (var item in aux.Asignaturas)
{
lstMaterias.Items.Add(item);
}
}