tags:

views:

293

answers:

3

I am implementing a Data Access Layer (DAL), which is basically a set of classes with (VB.NET) Shared functions to actually execute the database (CRUD) calls. I am trying to figure out the best place to place the calls to the DAL within the class hierarchy. Let me give an example.

Suppose I have a class Customer, with only standard ID, Name, Address1, etc. properties and maybe an overridden ToString function or so. I also have a DAL class with Shared methods, such as:

(pseudocode)

Namespace Dal

Public Class Customer

Public Shared Function Read(id As Integer) As Customer

Public Shared Function ReadList() As List(Of Customer)

Public Shared Sub Create(c As Customer)

'etc.

Now, I could call the Dal from the presentation layer like so:

Me.DataGridView1.Datasource = Dal.Customer.ReadList

However, is it not a good practice to have the presentation layer aware of the Dal at all? Should I instead put methods in the Customer object and call the Dal, like this?

Public Function ReadList() As List(Of Customer)
    Return Dal.Customer.ReadList()
End Sub

Public Sub Create()
    Dal.Customer.Create(Me)
End Sub

Would this be "cleaner" OOP? Or is it acceptable practice to let the presentation call the Dal, passing the business objects like my previous example:

Me.DataGridView1.Datasource = Dal.Customer.ReadList

Dim c As New Customer
c.Name = "Alpha Corporation"
c.Address1 = "123 Main Street"
Dal.Customer.Create(c)

Thanks for your feedback.

+4  A: 

The less your application knows about your DAL the better. There are several ways to do this and I think you are on the right track. I think you might want to look into the factory pattern for this implementation as you will be able to hide the DAL implementation behind the factory and return entities and collections of entities from the factory.

Andrew Hare
So, the factory would sit between the DAL and the presentation layer, with the presentation layer calling methods in the factory? Is this the same as the service layer referenced by duffymo?
HardCode
Sort of - the factory pattern is just a pattern - it can be implemented in the form of a service layer if you wish.
Andrew Hare
+2  A: 

I agree that data calls do not belong in a UI layer. Those are for presentation only.

I think they properly belong in a service layer. The service implementation uses model objects and the persistence layer to accomplish its goals. Whether that's an XML-based web service or local interface, the service is the object that maps to use cases and knows about units of work.

Either put the database calls into a separate persistence layer or embed them in the model objects for extra object-oriented purity.

duffymo
All three respondents gave great answers, but I have to choose one as correct. Thanks everyone!
HardCode
+1  A: 

The reason why'd you want to pull the CRUD operations into a separate layer is in case you ever want to change database systems. Well, that's why I did it. I wouldn't recommend doing this just to be good OOD. But here ya go...

Several sets of classes/interfaces

BusinessObject - Represents business type entities such as a Customer, has DataManager as a property.

DataManager - Maybe you can come up with a better name, but this thing provides Load() and Save() functions for the BusinessObjects

SearchList - Returns lists of things, your sql querries go here. Also this should probably behave like a RecordSet with Next(), Eof(), and CurrentRecord type members

Constructor/Factory - See FactoryPattern. You've de-coupled your database operations from your business objects this thing re-couples them in a necessary way. Assigns an appropriate datamanager implementation to BusinessObject

Come up with whatever actual names you want, but lets talk about Customer again. Suppose you have an Oracle database. You might end up with these classes:

boCustomer that inherits from BusinessObject

oracleDMCustomer that inherits or implements DataManager

searchlistCustomer that inherits from searchlist that has exposed either through abstract methods or as an interface something like: SearchAll() - which should return all customer SearchByZip(String zip) which should return all customers with the given zipcode

oracleSearchlistCustomer - implements searchlistCustomer, would actually implement the SearchAll() and SearchByZip()

boFactory - static class that has a method that looks something like CreateObject(Type type)

searchlistFactory - static class that has a method that looks something like CreateSearchList(Type type);

I'll let you fill in some of the blanks, but I think the important stuff is there. Others may have different ideas that require less abstraction. I'd mock up several strategies before going with one.

CrashCodes
Good stuff. Thanks!
HardCode