0

I'm trying to improve my application's design, So instead of calling the DataAccess layer from the presentation layer. I'll try to implement a save method from my object in the BusinessObjects layer. but I'm not sure how to pass the object or it's properties through the layers. for example in my old design I just create an instance of my object in the presentation layer and assign it's properties then just call the DataAccess method for saving this info in the database and pass the object as a parameter as illustrated.

DAL

public static void SaveObject(Object obj)
{
   int id = obj.id;
   string label = obj.label;
}

PL

Object obj = new Object();
obj.id = 1;
obj.label = "test";
DAL.SaveObject(obj); 

but I just want to do this in my PL

Object obj = new Object();
obj.id = 1;
obj.label = "test";
obj.SaveObject();

Is that possible? and how would my DAL look like ?

Edit: Explaining my requirements

I'll base my code right now on a very important object in my system.

BusinessEntitiesLayer uses BusinessLogic Layer

namespace BO.Cruises
{
    public class Cruise
    {
        public int ID
        { get; set; }

        public string Name
        { get; set; }

        public int BrandID
        { get; set; }

        public int ClassID
        { get; set; }

        public int CountryID
        { get; set; }

        public string ProfilePic
        { get; set; }

        public bool Hide
        { get; set; }

        public string Description
        { get; set; }

        public int OfficialRate
        { get; set; }

        public string DeckPlanPic
        { get; set; }

        public string CabinsLayoutPic
        { get; set; }

        public List<Itinerary> Itineraries
        { get; set; }

        public List<StatisticFact> Statistics
        { get; set; }

        public List<CabinRoomType> RoomTypesQuantities
        { get; set; }

        public List<CabinFeature> CabinFeatures
        { get; set; }

        public List<CruiseAmenity> Amenities
        { get; set; }

        public List<CruiseService> Services
        { get; set; }

        public List<CruiseEntertainment> Entertainment
        { get; set; }

        public List<CustomerReview> CustomerReviews
        { get; set; }
    }

}

BusinessLogicLayer uses DataAccessLayer

Actually this layer is intended to be validating my object then call the DAL methods but I didn't implement any validation right now, so I'm just using it to call the DAL methods.

    public static void Save(object cruise)
    {
        CruisesDAL.Save(cruise);
    }

DataAccessLayer trying to reference BussinessEntities but it's giving me circular dependencies error!

It's supposed to receive the object and cast it as Cruise entity

    public static void Save(object cruise)
    {
         Cruise c = cruise as Cruise;

         //access the object c properties and save them to the database
    }

Code sample from my project:

public static List<Cruise> GetCruisesList()
{
    string commandText = "SELECT ID, Name + CASE Hide WHEN 1 Then ' (Hidden)' ELSE '' END AS Name FROM Cruises";
    List<Cruise> cruises = new List<Cruise>();
    Cruise cruise;

    using (SqlConnection connection = new SqlConnection(ConnectionString))
    {
        using (SqlCommand command = new SqlCommand(commandText, connection))
        {
            connection.Open();

            using (SqlDataReader reader = command.ExecuteReader())
            {
                while (reader.Read())
                {
                    cruise = new Cruise();

                    cruise.ID = Convert.ToInt32(reader["ID"]);
                    cruise.Name = reader["Name"].ToString();

                    cruises.Add(cruise);
                }
            }
        }
    }

    return cruises;
}

PresentationLayer uses BusinessEntities

Input controls (TextBoxes, DropDownList, etc)

When the save button is clicked I take all the values, create a Cruise object and call Cruise.Save();

Mazen Elkashef
  • 3,430
  • 6
  • 44
  • 72
  • 1
    Extension methods will help you - http://msdn.microsoft.com/en-us/library/bb383977.aspx – rkg Sep 01 '11 at 22:22

3 Answers3

2

You should avoid mixing the domain model with the persistence logic. The examples given above would make a tight coupling solution. In order to achieve the .SaveObject() you can make extension methods in the BL that would do the job.

BL.*

public static class ObjectPersistanceExtensions{

       public static SaveObejct<T>(this IBaseEntity obj){

            IObjectDal<T> _dal = AvailableSerices.Obtain<IObjectDal<T>>();
            _dal.AddObject(obj);
            _dal.Commit();
       }
}

So in this way you can still add functionaries to the domain objects without coupling the logic in the domain objects.

1

if you follow this pattern you will have the saving logic inside the object definition itself, so when you call from PL:

obj.SaveObject();

this will happen in the Object itself:

public void SaveObject()
{
  DAL.SaveObject(this);
}

and your DAL stays the same as you shown above.

it's a matter of design, I would not put the logic of saving inside the object but I would have a BusinessManager or an ObjectMapper to read from DAL and save to DAL.

in general is a good practice to have read or load and Save in the same place, BusinessObject or BusinessManager, but together so you find them easily and update both in a breeze if you add or change a field.

Davide Piras
  • 43,984
  • 10
  • 98
  • 147
  • Well, actually I have BusinessLogic layer .. the Object.Save() calls ObjectBLL.Save() and it verifies the data then send it to the DAL.Save(object obj). that's of course what I'm trying to implement but it's giving me a circular dependencies error and of course it's essential to use my Entities Layer in the DataAccess layer. anyway I'm not very good with the design, so could just post some samples to illustrate how and where would you implement the Save method and which layers would you choose ? – Mazen Elkashef Sep 01 '11 at 22:36
  • One of the main rules in a n-tier approach is to do not reference everything from everything. PL references ONLY BL and BL (Business Logic) references DAL, DAL is not available ever to the PL, no circular references. Entities are then defined in a separated class library called Core or Common, for example, and referenced by all layers. We also use separated class libraries for entities and interfaces, PL only references Interfaces, BL both, creates entities and returns Interfaces to the PL. Quite solid! – Davide Piras Sep 01 '11 at 22:41
  • I Understand but I have 4 layers now, each in a separate project. PL, BO, BL, DAL .. I'm aware on how to reference 3 layers but how about now ? and do you think to implement a save method in the Objects layer is a good thing. I just thought it would be good to make the save method non-static instead of just calling the BLL or the DAL method directly – Mazen Elkashef Sep 01 '11 at 23:02
  • I'm curious how come PL don't reference BusinessObjects .. I think it's very important so I could send the DAL my object and then it would be able to see the object properties and add them to my SqlCommand as parameters then excute it .. am I missing something ? – Mazen Elkashef Sep 01 '11 at 23:12
  • PL knows the properties because knows the interface implemented by the object. BL knows everything and instantiates entities but returns interfaces, DAL could live knowing only Interfaces. As David Anderson says in the end is about requirements. How many different entities do you have in your project and how big is the project... – Davide Piras Sep 01 '11 at 23:16
  • Well, I'm not sure about what do you mean by "DAL could live knowing only Interfaces." .. please check now my question I updated the DAL part with a copy from my project. I just can't imagine how can I implement the DAL without seeing the properties so I could access the values and place them in my query. right now I have like 3 other entities. and I hope you could talk from the perspective of 4 layers so I could be able to apply your advice in my design as I have to business layers (Entities and Logic/Rules) or should I place them both in one assembly ? – Mazen Elkashef Sep 01 '11 at 23:31
  • Sorry, I Think I got you. DAL will reference the IEntities, so it will be able to see the object attributes. – Mazen Elkashef Sep 02 '11 at 00:36
  • I've been trying to implement two business objects, BO and IBO .. but when I wanted to update my DAL I couldn't of course create an instance from ICruise! .. so I take ICruise as a parameter and then what, how am I supposed to get the values I think I still an object right or how exactly does it work!? and of course I'll face the same problem when trying to create an object from Cruise in my PL so I could save it! – Mazen Elkashef Sep 02 '11 at 01:10
1

Passing the object itself to the data layer is usually a bit funky. Instead, I recommend that you have the object do the talking to the data layer, and let the data layer do its thing.

internal static class DataLayer {

    public static bool Update(int id, string label) {
        // Update your data tier
        return success; // bool whether it succeeded or not
    }
}

internal class BusinessObject {

    public int ID {
        get;
        private set;
    } 

    public string Label {
        get;
        set;
    } 

    public bool Save() {
        return DataLayer.Update(this.ID, this.Label); // return data layer success
    }
}

The reason you would do it this way, is because your data layer may not have a reference to your business object, and thus would have no idea what it is. You would not be able to pass the object itself. This is a usual scenerio because generally it is your business object assembly that references your data layer assembly.

If you have everything in the same assembly, than the above does not apply. Later on however, if you decide to refactor your data layer into its own module (which is often how it turns out, and is good design), passing the object will break because then it loses its reference to your business object.

Either way you do it, you should know that you will have to update both your object and your data layer if you add a new field or member. That's just a given when you add something new.

I may write a blog on some good design practices for this, but that is my recommendation.

David Anderson
  • 13,558
  • 5
  • 50
  • 76
  • I see where you are going, but I dislike the idea of listing all members in the method signature, we should pass classes and have properties encapsulated, what if you have 25 members!? Also, your DAL is not generic, what if two objects have an int and a string? – Davide Piras Sep 01 '11 at 22:37
  • The Article would be GREAT! :) seriously. I need to learn good design but it's all in complicated and huge books! .. and about my layers I have 4 layers each one in a separate assembly in my solution. I'm not sure whether I understand you on passing the object thing. but I need my DAL to use the BusinessEntites assembly and I don't send the properties as parameters because they are a lot! and if I made any changes to my object I'll need to edit a lot. Maybe that's what you're trying to say, sometimes I get lost in the answers, sorry about that – Mazen Elkashef Sep 01 '11 at 22:42
  • @Davide Piras, If a object has 25 members, than you probably would not design it this way. Design is often done based on requirements, and the requirements in his post are very basic and vague as well. There are many design patterns you can choose to architect and implement, but it all comes back to requirements. at IKashef I will write one later today. My Url is in my profile – David Anderson Sep 01 '11 at 22:43
  • I think now that we both agree that I don't pass the object parameters separately in the method parameters – Mazen Elkashef Sep 01 '11 at 22:43
  • Could you explain a little bit more on your objects, requirements so we can suggest a proper design pattern? I will write a blog later today, but if you need an answer some more details would be awesome – David Anderson Sep 01 '11 at 22:45
  • yh my object would have like 25 properties. and I know there are many patterns but I really need help, hints, articles. anything to help me understand the suitable pattern for my application and how to implement it. – Mazen Elkashef Sep 01 '11 at 22:45
  • Ok I'll try right now to edit my question with more details about my application, and I hope it would help making my design less vague. – Mazen Elkashef Sep 01 '11 at 22:46
  • 1
    It is. When I am finished polishing up these web forms I will take a looksy and respond. – David Anderson Sep 02 '11 at 00:30
  • Do you have Skype IKashef? If you do hit me up http://www.dcomproductions.com/contact/ (click the skype button at the very bottom) – David Anderson Sep 02 '11 at 01:32
  • I did but you're not online .. sorry it took me that long, the website didn't show the notification! – Mazen Elkashef Sep 02 '11 at 01:58
  • Thank you so much David .. I'm sorry I've been busy those past days .. I'll update the question with the answer that I've got from you and if you have the time just to share your opinion about HyBRiDHeLL's answer. – Mazen Elkashef Sep 05 '11 at 04:17