Implement a Save method for my object - c#

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();

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.

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.

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.

Related

Is it possible to have extra (ignored) properties in C#?

I have a repository for a DocumentDb database. My documents all have a set of common properties so all documents implement the IDocumentEntity interface.
public interface IDocumentEntity {
[JsonProperty("id")]
Guid Id { get; set; }
[JsonProperty("documentClassification")]
DocumentClassification DocumentClassification { get; set; }
}
public class KnownDocument : IDocumentEntity {
[JsonProperty("id")]
Guid Id { get; set; }
[JsonProperty("documentClassification")]
DocumentClassification DocumentClassification { get; set; }
[JsonProperty("knownProperty")]
string KnownProperty { get; set; }
}
public class BaseDocumentRepository<T> where T : IDocumentEntity {
public Set(T entity) {
// ... stuff
}
}
This works fine with a KnownDocument where I know all of the properties. But, of course, what's great about a Document Db is that I don't need to know all of the properties (and in many cases I won't).
So my client submits something like this-
{unknownProperty1: 1, unknownProperty2: 2}
And I want to upsert this using my document repository.
public OtherDocumentService() {
_otherDocumentService = new OtherDocumentRepository();
}
public UpsertDocument(dynamic entity) {
entity.id = new Guid();
entity.documentClassification = DocumentClassification.Other;
_otherDocumentRepository.Set(entity);
}
But I get an InvalidCastException from dynamic to IDocumentEntity. I assume it's because of the extra properties that exist on the dynamic object but not on the IDocumentEntity interface?
What I'm trying to do is leave my document entities open to be dynamic, but rely on a few properties being there to maintain them.
Entity parameter passed to the UpsertDocument should explicitly implement IDocumentEntity in order do make the code works, it is not enough just have a Id property.
Some options:
1) Proxy may be applied:
public class ProxyDocumentEntity : IDocumentEntity
{
public dynamic Content { get; private set; }
public ProxyDocumentEntity(dynamic #content)
{
Content = #content;
}
public Guid Id
{
get { return Content.Id; }
set { Content.Id = value; }
}
}
... using
public void UpsertDocument(dynamic entity)
{
entity.Id = new Guid();
repo.Set(new ProxyDocumentEntity(entity));
}
The stored document will have nested Object property, which may be not acceptable
2)There is a lib https://github.com/ekonbenefits/impromptu-interface which creates a proxy dynamically
and does not make extra property like solution above.
Drawback will be in performance.
Technically it could be 2 methods:
public void UpsertDocument(IDocumentEntity entity){...}
public void UpsertDocument(dynamic entity){...}
so the first (fast) will work for the objects which implement IDocumentEntity and second(slow) for the rest of the objects.
But this is a speculation a bit , as I dunno the details of the whole code base of the project you have.
If you have some flexibility as to how to name those dynamic properties, you could stuff them into a Dictionary property on your object:
public Dictionary<string, dynamic> extra { get; set; }

ViewModel Object Convert to Entity Framework Object

Goal: to save ViewModel object by Entity Framework. I have UserViewModel object which has list of UnitViewModel. Then, I have a UserAdapter class which converts UserViewModel into Entity Framework User object (see Convert()below how).
Now, my question is how do I convert this list of UnitViewModel to its corresponding Entity Framework Unit list? - Do I have to get each object from DB Context by calling something like context.Units.Where(u=>myListofUnitIDs.Contains(u.UnitID))?
public class UserViewModel
{
public Guid? UserID { get; set; }
public string UserName { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Password { get; set; }
public DateTime? CreateTime { get; set; }
public List<UnitViewModel> UserUnits { get; set; }
}
public class UnitViewModel
{
public Guid UnitID { get; set; }
public string Name { get; set; }
public int? SortIndex { get; set; }
public DateTime CreateTime { get; set; }
public bool Assigned { get; set; }
}
public class UserAdapter
{
public static User Convert(UserViewModel userView)
{
User user;
if (userView.UserID.HasValue)
{
using (var provider = new CoinsDB.UsersProvider())
{
user = provider.GetUser(userView.UserID.Value);
}
}
else
{
user = new User();
}
user.FirstName = userView.FirstName;
user.LastName = user.LastName;
user.Password = StringHelper.GetSHA1(userView.Password);
user.UserName = user.UserName;
user.CreateTime = DateTime.Now;
// Problem here :)
// user.Units = userView.UserUnits;
return user;
}
}
UPDATE: The main concern here is that I have to retrieve each Unit from database to match (or map) it with ViewModel.Unit objects, right? Can I avoid it?
For your information, this operation is called as Mapping mainly. So, you want to map your view model object to the entity object.
For this, you can either use already existed 3rd party library as AutoMapper. It will map properties by reflection which have same name. Also you can add your custom logic with After method. But, this approach has some advantages and disadvantages. Being aware of these disadvantages could help you to decide whether you must use this API or not. So, I suggest you to read some articles about advantages and disadvantages of AutoMapper especially for converting entities to other models. One of such disadvantages is that it can be problem to change the name of one property in the view model in the future, and AutoMapper will not handle this anymore and you won't get any warning about this.
foreach(var item in userView.UserUnits)
{
// get the mapped instance of UnitViewModel as Unit
var userUnit = Mapper.Map<UnitViewModel, UserUnit>(item);
user.Units.Add(userUnit);
}
So, I recommend to write your custom mappers.
For example, I have created a custom library for this and it maps objects lik this:
user.Units = userView.UserUnits
.Select(userUnitViewModel => userUnitViewModel.MapTo<UserUnit>())
.ToList();
And I am implementing these mapping functions as:
public class UserUnitMapper:
IMapToNew<UnitViewModel, UserUnit>
{
public UnitViewModel Map(UserUnit source)
{
return new UnitViewModel
{
Name = source.Name,
...
};
}
}
And then in runtime, I am detecting the types of the objects which will be used during mapping, and then call the Map method. In this way, your mappers will be seperated from your action methods. But, if you want it urgently, of course you can use this:
foreach(var item in userView.UserUnits)
{
// get the mapped instance of UnitViewModel as Unit
var userUnit= new UserUnit()
{
Name = item.Name,
...
};
user.Units.Add(userUnit);
}

How to return specific set of data from a class

I have a similar structure to the one below
Base class
public class BaseClass
{
public string Name { get; set; }
public string Address { get; set; }
public int Age { get; set; }
public Guid Guid { get; set; }
public string Hometown { get; set; }
}
Derived Class
public class DerivedClass : BaseClass
{
public List<DerivedClassDataItem> Data { get; set; }
}
Data class
public class DerivedClassDataItem
{
public string Datum1 { get; set; }
public string Datum2 { get; set; }
public string Datum3 { get; set; }
public string Datum4 { get; set; }
public int Datum5 { get; set; }
public DateTime Datum6 { get; set; }
}
What is the best practice to return specific set of info from the DerivedClass?
a potential set could be:
Name, Address, Guid and then a Data list that only contains Datum1 and Datum4
I could see anonymousTypes, Tuples or another set of class(es), all to be valid approaches.
My concern about creating new set of classs for the set returned is that the class(s) structure will be similar to the structure of the three mentioned above except it will have fewer selected members, which to me, does not sound ideal. (duplicate code and structure)
Using anonymousTypes was my initial solution to tackle this, something like
List<DerivedClass> list = new List<DerivedClass>();
var mySet = list.Select(d => new
{
Name = d.Name,
Address = d.Address,
.
.
.
.
.
Data = d.Data.Select(item => new
{
Datum1 = item.Datum1,
Datum4 = item.Datum4
})
});
but again, that was a headache for us to track through httpResponse and through out API calls.
Should I go with Tuple?
Any insights as to what is the best practice for doing this?
Edit
I am using this set of data to be a response returned by a API/GET call. I will send the set back using HttpRespose and then the framework will transform that into json
this is an actual method we have now
private void populateReturnFile()
{
var returnFileAnonymous = new
{
Vendor = this.Vendor,
OrganizationName = this.OrganizationName,
User = this.User,
Platform = this.Platform,
DictionaryType = this.DictionaryType,
UseCaseId = this.UseCaseId,
Data = this.Data.Select(d => new
{
MigrationTermId = d.MigrationTermId,
ImoLexicalCode = d.ImoLexicalCode
})
};
this.returnFile = returnFileAnonymous;
}
Then my GET will return the retunFile (this is a very simple method, i have remove irrelevant code)
[HttpGet]
public HttpResponseMessage Get(Guid migrationFileId)
{
ProblemList problemList = ProblemList.GetProblemList(migrationFileId);
return Request.CreateResponse(HttpStatusCode.OK, problemList.ReturnFile, new JsonMediaTypeFormatter());
}
If API calls is where you are using these classes, then I personally like to keep it simple and avoid complex inheritance hierarchy. Remember, simple code is good code.
I would make a separate class for each api request/response call. For very simple api calls (ajax requests for example) I like to use anonymous types, but for controllers that only handle API calls I like to create separate classes, organized in a nice folder structure.
Everyone has their "style" but as long as you strive for simplicity your code will be maintainable.

Multiple View Models with Business Logic

Based off of the example located here:
Multiple ViewModels in View
Can anyone show this example without adding the individual items but by showing a datasource. So for instance if my business Logic layer has the means to pull the customer address then my two models would be CustomerInfo & CustomerLocations - doing it this way I am having trouble with the last line shown (the .Add) .. I tried removing the ToList but either way it says I have invalid arguements - my ViewModel class looks exactly like the example.
var ccus = new List<ViewModel.CustomerInfo>();
var cloc = new List<ViewModel.CustomerLocations>();
var cust = new ViewModel.Customers();
var cI1 = new Business.CustomerLogic.BLCustomerAddress();
cI1.LoadCustomerAddress(decryConcept, decryBnumber, intCustid).ToList();
ccus.Add(cI1);
In the previous example he declares the code inline
var car1 = new Car
{
Id = 1,
Name = "Passat"
};
I want to replace this piece with a call to my Business Logic
I have no reference to the BusinesLogic model in the new ViewModel I have setup per the example and perhaps this is where I need to tie the two objects together. Here is my code for that piece.
public class ViewModel
{ public class Customers
{ public IEnumerable<CustomerInfo> CInfo { get; set; }
public IEnumerable<CustomerLocations> CLoc { get; set; }
}
public class CustomerInfo
{
public int CustomerID { get; set; }
public string AccountNo { get; set; }
public bool Active { get; set; }
public string Company { get; set; }
.........
ccus is of type List<ViewModel.CustomerInfo> so the add method expects a ViewModel.CustomerInfo but you are passing in cI1 which is of type Business.CustomerLogic.BLCustomerAddress. Calling ToList() won't do anything as you are not storing the result of LoadCustomerAddress, so turning the result into a list has no affect on anything.

Data transfer object pattern

i'm sorry i'm newbie to enterprise application as well as the design pattern. might be this question occcur lack of knowledge about design pattern. i found that its better to use DTO to transfer data.
my business entity class as below:
public class Patient
{
public string ID { get; set; }
public string FullName { get; set; }
public string FirstName { get; set; }
public string Surname { get; set; }
}
so in my application user only give ID and HospitalID. so it calls for another web service and get person information
public class PersonDTO
{
public string NIC { get; set; }
public string FullName { get; set; }
public string FirstName { get; set; }
public string BirthPlace { get; set; }
public string BirthCertificateID { get; set; }
}
so based on these information im going to Patient object. (Using DTO pattern)
so i thought of write new class to convert this as follows.
public class PatientDO
{
public static Patient ConvertToEntity(
PatientRegistrationDTO pregDTO,
PersonDTO person
)
{
Patient p = new Patient();
p.NIC = pregDTO.NIC;
p.FullName = person.FullName;
p.FirstName = person.FirstName;
return p;
}
}
but lately i read few articles and they used Serializer Helper class as well as the XmlSerializer i can't understand why they used somthing like that.
for the DTO pattern is that need to use XmlSerializer and why it is used?
You should really take a look at AutoMapper.
http://automapper.org
This is a piece of software that you can include in your solution that will automatically map values from one class to another.
It'll map properties with the same name automatically, and is also pretty smart when it comes to child objects. However, it also offers complete mapping control when you need it.
EDIT
Couple of examples to show how AutoMapper works. Please note I'd never code like this in real life. Brevity!
Example classes.
// Common scenario. Entity classes that have a connection to the DB.
namespace Entities
{
public class Manager
{
public virtual int Id { get; set; }
public virtual User User { get; set; }
public virtual IList<User> Serfs { get; set; }
}
public class User
{
public virtual int Id { get; set; }
public virtual string Firstname { get; set; }
public virtual string Lastname { get; set; }
}
}
// Model class - bit more flattened
namespace Models
{
public class Manager
{
public int Id { get; set; }
public string UserFirstname { get; set; }
public string UserLastname { get; set; }
public string UserMiddlename { get; set; }
}
}
Typically, you'd have a part of your project to configure all your AutoMapping. With the examples I've just given, you can configure a map between Entities.Manager and Models.Manager like so:-
// Tell AutoMapper that this conversion is possible
Mapper.CreateMap<Entities.Manager, Models.Manager>();
Then, in your code, you'd use something like this to get a new Models.Manager object from the Entity version.
// Map the class
var mgr = Map<Entities.Manager, Models.Manager>
( repoManager, new Models.Manager() );
Incidentally, AM is smart enough to resolve a lot of properties automatically if you name things consistently.
Example above, UserFirstname and UserLastname should be automatically populated because:-
Manager has a property called User
User has properties called Firstname and Lastname
However, the UserMiddlename property in Models.Manager will always be blank after a mapping op between Entities.Manager and Models.Manager, because User does not have a public property called Middlename.
There is a nice, yet simple demo in CodeProject. It is worthy going through it.
Newbies can get a basic idea of designing DTOs.
http://www.codeproject.com/Articles/8824/C-Data-Transfer-Object
Here's a summary of the content:
The Data Transfer Object "DTO", is a simple serializable object used to transfer data across multiple layers of an application. The fields contained in the DTO are usually primitive types such as strings, boolean, etc. Other DTOs may be contained or aggregated in the DTO. For example, you may have a collection of BookDTOs contained in a LibraryDTO. I have created a framework used by multiple applications that utilizes DTOs to transfer data across tiers. The framework also relies on other OO patterns such as the Factory, Facade, etc. One of the great things about the DTO compared to a DataSet is that the DTO does not have to directly match a data table or view. The DTO can aggregate fields from another DTO
This is the base class for all Data Transfer Objects.
using System;
namespace DEMO.Common
{
/// This is the base class for all DataTransferObjects.
public abstract class DTO
{
public DTO()
{
}
}
}
This is a derived class from DTO:
using System;
using System.Xml.Serialization;
using DEMO.Common;
namespace DEMO.DemoDataTransferObjects
{
public class DemoDTO : DTO
{
// Variables encapsulated by class (private).
private string demoId = "";
private string demoName = "";
private string demoProgrammer = "";
public DemoDTO()
{
}
///Public access to the DemoId field.
///String
[XmlElement(IsNullable=true)]
public string DemoId
{
get
{
return this.demoId;
}
set
{
this.demoId = value;
}
}
///Public access to the DemoId field.
///String
[XmlElement(IsNullable=true)]
public string DemoName
{
get
{
return this.demoName;
}
set
{
this.demoName = value;
}
}
///Public access to the DemoId field.
///String
[XmlElement(IsNullable=true)]
public string DemoProgrammer
{
get
{
return this.demoProgrammer;
}
set
{
this.demoProgrammer = value;
}
}
}
This is the helper class for a DTO. It has public methods to serialize and de-serialize a DTO.
using System;
using System.Xml.Serialization;
using System.IO;
namespace DEMO.Common
{
public class DTOSerializerHelper
{
public DTOSerializerHelper()
{
}
///
/// Creates xml string from given dto.
///
/// DTO
/// XML
public static string SerializeDTO(DTO dto)
{
try
{
XmlSerializer xmlSer = new XmlSerializer(dto.GetType());
StringWriter sWriter = new StringWriter();
// Serialize the dto to xml.
xmlSer.Serialize(sWriter, dto);
// Return the string of xml.
return sWriter.ToString();
}
catch(Exception ex)
{
// Propogate the exception.
throw ex;
}
}
///
/// Deserializes the xml into a specified data transfer object.
///
/// string of xml
/// type of dto
/// DTO
public static DTO DeserializeXml(string xml, DTO dto)
{
try
{
XmlSerializer xmlSer = new XmlSerializer(dto.GetType());
// Read the XML.
StringReader sReader = new StringReader(xml);
// Cast the deserialized xml to the type of dto.
DTO retDTO = (DTO)xmlSer.Deserialize(sReader);
// Return the data transfer object.
return retDTO;
}
catch(Exception ex)
{
// Propogate the exception.
throw ex;
}
}
}
Now begin Serialization / Deserialization:
using System;
using DEMO.Common;
using DEMO.DemoDataTransferObjects;
namespace DemoConsoleApplication
{
public class DemoClass
{
public DemoClass()
{
}
public void StartDemo()
{
this.ProcessDemo();
}
private void ProcessDemo()
{
DemoDTO dto = this.CreateDemoDto();
// Serialize the dto to xml.
string strXml = DTOSerializerHelper.SerializeDTO(dto);
// Write the serialized dto as xml.
Console.WriteLine("Serialized DTO");
Console.WriteLine("=======================");
Console.WriteLine("\r");
Console.WriteLine(strXml);
Console.WriteLine("\r");
// Deserialize the xml to the data transfer object.
DemoDTO desDto =
(DemoDTO) DTOSerializerHelper.DeserializeXml(strXml,
new DemoDTO());
// Write the deserialized dto values.
Console.WriteLine("Deseralized DTO");
Console.WriteLine("=======================");
Console.WriteLine("\r");
Console.WriteLine("DemoId : " + desDto.DemoId);
Console.WriteLine("Demo Name : " + desDto.DemoName);
Console.WriteLine("Demo Programmer: " + desDto.DemoProgrammer);
Console.WriteLine("\r");
}
private DemoDTO CreateDemoDto()
{
DemoDTO dto = new DemoDTO();
dto.DemoId = "1";
dto.DemoName = "Data Transfer Object Demonstration Program";
dto.DemoProgrammer = "Kenny Young";
return dto;
}
}
Finally this code is executed in the main application
static void Main(string[] args)
{
DemoClass dc = new DemoClass();
dc.StartDemo();
}
An XmlSerializer or JsonSerializer can be used for serializing (loading) XML or Json data from a source (webservice). Or explaining the name DTO: you serialize (transfer) data from a source (webservice) to a (general DTO) object. So DTOs are general purpose objects. Sometimes its clever to make a wide as possible DTO object and fill that completely so you can use from that object whatever you like and copy that to your "own" program objects.
Example: I developped a program for showing transport navigation data. I serialize the whole xml or json messsage in a DTO object. In this DTO object is more information then I will need in my program and it can be in a different form, so I will use only whats needed. DTO objects makes it more easy to extract data from sources (webservices).
I dont want to use AutoMapper because of the name "Auto". I want to know what I am doing and think where my data is going to.

Categories