问题
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();
回答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.
回答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.
回答3:
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.
来源:https://stackoverflow.com/questions/7277228/implement-a-save-method-for-my-object