If you are developing n-tier application sooner or later you will find yourself in a situation where you need to move data between the tiers. Be it from the lowest tier - i.e.: the data tier or data access layer (DAL) to a middle tier such as business logic layer (BLL) or the other way around. So how to accomplish this task?
Actually there are many problems with moving data between tiers, especially if you like a clean OOP with a full domain model. Suppose you have a domain object filled with all the necessary methods such as a Teacher who can Grade Students. Now with this logic you also have the data such as Name for both the Sudent and the Teacher. That is your BLL. Now you also have a DAL in which you would like to have a method such as GetTeacherById or SaveStudent. What should those methods return (or accept as a parameter)? The easy answer is - your BLL objects. This implies the referrence from the DAL to BLL - which is wrong since most people will tell you that every layer should only reference the layer below. I agree with this recommendation completly. If you think about a situation where you would like to have some kind of lazy load mechanism for properties of your BLL objects or a simple method call that gets the data from the database such as Teacher.GetGradedStudents, you would have to have a referrence from BLL to DAL.
So is it possible to at the same time have a referrence from DAL to BLL and from BLL to DAL? In .NET it is not possible as long as both are in separate projects. This situation is called a Circular Refference and Visual Studio will not allow you to do it if you try.
So how to solve this issue? Surely there has to be a solution... There are many solutions to the problem. Microsoft has its way described in their article on Designing Data Tier Components and Passing Data Through Tiers. It is a good overview of the problem, but Microsoft being Micorosft has its way of thinking. After all they are the ones that promote the DataSet/DataTable objects.
In short: what you need is an additional component which I will call a Data Transfer Object (DTO). The DTO will be refferenced by both BLL and DAL but will not reference neither BLL nor DAL. This way we have no circular refference problem. The DTO objects will represent only the data, with no behavior. A DataSet/DataTable is an example of such an object. So is the DataReader or an XmlDocument. You can use any of the mentioned objects to move data from your DAL up to BLL, but it gets a little more difficult to do it the other way. More over, if you are not using Typed DataSets, how would you know how to access the name property of the Teacher object? By using an Indexer and a string argument to represent the column name? How do you know what columns are there in the database? Why do you need this knowledge in the BLL? You do not need it! Even more! It is a violation of the rule that the layer should only know about the layer immediatly below, but the database which dictates the column names is not directly below BLL it is below DAL. So not typed DataSets do not shield you from the database and that is why I think they are wrong. A better solution would be to use a strongly typed objects defined in a separate project. So for example there will be a Teacher class in the DTO with a Name property but without a Grade method.
As an example I have prepared a sample solution with 3 projects: BLL, DAL and DTO. You can download the sample here: DTOExample.zip (7.29 KB).
Keep in mind that the example presents only the simpliest scenario where BLL objects know about DAL and how to save themselves. In a real application it will most likely not be the case.