views:

118

answers:

5

Hi Guys, What is the best approach to implement a CRUD on the BL using interface that will be used to abstract DAL operations? I need your opinion guys..

Here's my draft..

Data Entities that are mapped in the database table

 public class Student
 {
    public string StudentId { get; set; }
    public string StudentName { get; set; }
    public Course StudentCourse { get; set; }
 }

 public class Course
 {
    public string CourseCode { get; set; }
    public string CourseDesc { get; set; }
 }

I created an CRUD Interface to abstract the object's operations

public interface IMaintanable<T>
{
   void Create(T obj);
   T Retrieve(string key);
   void Update(string key);
   void Delete(string key);
 }

And then a component that manages the Entity and its operations by implementing the interface

public class StudentManager : IMaintainable<Student>
{
    public void Create(Student obj)
    {
        // inserts record in the DB via DAL
    }

    public Student Retrieve(string userId)
    {
        // retrieveds record from the DB via DAL
    }

    public void Update()
    {
        // should update the record in the DB
    }

    public void Delete(string userId)
    {
        // deletes record from the DB
    }
}

sample usage

    public void Button_SaveStudent(Event args, object sender)
    {
        Student student = new Student()
        {
           StudentId = "1", StudentName = "Cnillincy"
        }

        new StudentManager().Create(student);   
     }

as you can see, there is quite an abnormalities on the update method

    public void Update()
    {
        // should update the record in the DB
    }

what should this method have to update the objects property? should I inherit the Student?

    public class StudentManager : Student , IMaintainable<Student>
    {
        public void Update()
        {
            //update record via DAL
         }
    }


    public void Button_SaveStudent(Event args, object sender)
    {
        Student student = new StudentManager();
        student.StudentId = "1";
        student.StudentName = "Cnillincy"
        student.Update()
    }

Or should I just contain the Student class as an attribute of the Student manager?

     public class StudentManager : IMaintainable<Student>
    {
        public Student student { get; private set };

        public void Create() {}
        public void Update() {}
        public void Retrieve() {}
        public void Delete() {}
    }

Which more appropriate? What about the interface? Any other suggestions guys? thanks..C

+1  A: 

Your CRUD interface should probably look like

public interface IMaintanable<T>
{
    string Create(T obj);
    T Retrieve(string key);
    void Update(T obj);
    void Delete(string key);
}

that is, both Create and Update take a copy of the object you're updating. The difference is that the Update can get the key from the obj, so it knows which object it's changing. Create would normally cause the key to be created so you pass it back as a return value. Hope that helps.

(The Update might also pass back the key too.)

Lunivore
do you thinks it's more efficient than inheriting the object, because it means that youll create another copy of the obj instead of just updating it,,
CSharpNoob
Inheriting wouldn't make sense. Your StudentManager IS NOT a student.
Matthieu
What Matthieu said. Think of the student like a record and your StudentManager like the headmaster's secretary, typing the records up as they come in. Single Responsibility Principle FTW.
Lunivore
A: 

I wouldn't make StudentManager inherit Student, I would make my Update method stateless like your create method, i.e.

public interface IMaintanable<T>
{
  void Create(T obj);
  T Retrieve(string key);
  void Update(T obj);
  void Delete(string key);
}

and

public void Update(T obj)
{
  // should update the record in the DB
}
JonoW
could you explain why this the more appropriate than inheriting or attributing the DataEntity? thanks
CSharpNoob
For me its down to OO "correctness" and seperation of concerns; A StudentManager is not a Student (in an OO sense). The Student classes responsibility is to model the data, the StudentManagers responsibility is to persist that data, I just think those shouldn't mixed. But thats just my opinion, I may not be right :)
JonoW
A: 

I saw this from Rob Conery that I really like. It's power is in the flexibility of the arguments you can pass to the methods. Your implimentation isn't robust enough IMO. Check out his MVC starter kit here http://mvcstarter.codeplex.com/ (It's called ISession there).

public interface IMaintainable : IDisposable
    {
       T Single<T>(Expression<Func<T, bool>> expression) where T : class, new();
       System.Linq.IQueryable<T> All<T>() where T : class, new();
       void Add<T>(T item) where T : class, new();
       void Update<T>(T item) where T : class, new();
       void Delete<T>(T item) where T : class, new();
       void Delete<T>(Expression<Func<T, bool>> expression) where T : class, new();
       void DeleteAll<T>() where T : class, IEntity, new();
       void CommitChanges();
    }
James South
this is like IEnumerable<T> extension methods .. thanks
CSharpNoob
No worries... Once you have a look at his solution you'll see how little code you really need to do most CRUD operations.
James South
+1  A: 

Personally, I think that all you are missing is the appropriate terminology. What this really is an approximation of a very helpful pattern, called the repository pattern. As far as type-awareness, goes, the implementation would be referred to as a generic repository.

The way I have personally implemented in the past was to have an interface defining the repository, such as IRepository<T>, and a base class that is specific to the type of repository, such as a SqlRepositoryBase<T>. The reason that I would do this is that I can put the implementation-specific code in the base class. So, the plumbing is done and I can worry about domain-specific implementation in the final repository, which would be StudentRepository, a SqlRepository<Student> (or SqlRepository<IStudent> if you define interfaces for your entity).

It seems that you are concerned about how many objects are instansiated, and I can tell you that you are not generating a significant enough drain on resources to really be concerned about implementing in this fashion. Old-timers might cringe at the fact, but we are not trying to optimize for 64k or RAM anymore. ;-) It is more about maintainability, code contracts, etc.

Not to add uneeded complexity up-front, but you also might want to look into the Unit of Work Pattern if you are looking at enlisting multiple entities of different types into atomic transactions.

Here are a couple of good references for these topics:

Two takeaways from this in general (IMHO):

  • I personally disagree with the assumption that a Repository pattern approach only has usefulness in larger projects; especially the Generic Repository pattern. If you start putting code like this into a reusable library, you will be surprised at how quickly you can start creating an invaluable resource of building blocks.

  • The biggest plus from this approach is the sheer testability of it; even more so than the reusability. If you are looking to mock out your repositories for any sort of a TDD approach, you can do so with little effort. This will allow you to write richer tests around the usages of the repositories throughout your code.

joseph.ferris
A CRUD pattern like this is basically a repository pattern anyway, whatever you might call it. I agree with your comment about it being useful even for small projects. The good thing about approaching it from a CRUD point of view is that it translates really nicely to REST. REST, even done poorly, is pretty performant and scalable. With a domain like students - accessed heavily for only a few days each year - performance could actually be a consideration, even if it's not a differentiator.
Lunivore
A: 

Take a look at the new Entity Framework 4 that was recently released. They are featuring a "code by convention" model that allows you to easily map your business objects directly to the database without having to worry about a DAL.

"The Gu" has a great series outlining how easy it is to map your objects, and even do some simple modifications when linking to the database through the DbContext model it uses.

It is worth noting that the current release is at CTP4, but I anticipate most of the issues have already been worked out with the framework and should serve you well.

Dillie-O