I have created a base class as "Common" there are many properties such as pageno,pagesize,search,etc which will use in all classes for entire project(must require).
There is other class as "Area" which extends "Common" class.
All properties are automatic get and set.
Here the problem is,
I have created web api.It returned object of Area class.
So here client received all properties of area and common.But I need specific properties to response.
Means I just need two properties of Area i.t AreaId,AreaName
This requirement for retuned data in different format like JSON and XML.I did with linq it gives specific properties Which I need exactly. But It is anonymous type data. Not strongly object.
following sample of my code
public class Common
{
public int CaseNo { get; set; }
public int? RET_ID { get; set; }
public string MSGSTATUS { get; set; }
public string MSG { get; set; }
public int? LoginId { get; set; }
}
public class Area : Common
{
public int AreaId { get; set; }
public string AreaName { get; set; }
public string PinCode{ get; set; }
}
/Web api code/
public IHttpActionResult GetAreaById(int AreaId, int LoginId)
{
try
{
AreaDAL objDal = new AreaDAL();
Area objBo = new Area();
objBo = objDal.EditArea(AreaId, LoginId);
if (objBo != null)
{
/*Not working for xml returned data(work for json).anonymous type data*/
return ResponseMessage(Request.CreateResponse(HttpStatusCode.OK, new Area { AreaId = objBo.AreaId, AreaName = objBo.AreaName }));
/*working for json and xml */
/*But it retuned all properties of Area and common*/
/*Needed as AreaId and AreaName*/
return ResponseMessage(Request.CreateResponse(HttpStatusCode.OK, objBo));
}
}
Introduce an intermediate class (AreaInfo) and pull AreaId and AreaName members up:
public class AreaInfo : Common
{
public int AreaId { get; set; }
public string AreaName { get; set; }
}
public class Area : AreaInfo
{
public string PinCode{ get; set; }
}
//...
public IHttpActionResult GetAreaById(int AreaId, int LoginId)
{
try
{
AreaDAL objDal = new AreaDAL();
Area objBo = new Area();
objBo = objDal.EditArea(AreaId, LoginId);
if (objBo != null)
{
return ResponseMessage(Request.CreateResponse(HttpStatusCode.OK, new AreaInfo { AreaId = objBo.AreaId, AreaName = objBo.AreaName }));
return ResponseMessage(Request.CreateResponse(HttpStatusCode.OK, objBo));
}
}
edit: for hiding fields in the Common base class, you can:
1) Change their access modifier (e.g. to protected)
2) Mark them with attributes to be skipped on serialization like:
[XmlIgnore] for xml serialization
[JsonIgnore] for json serialization
3) Separate the class hierarchies (Common from AreaInfo<-Area) and use composition for when you need
extra fields in Common class.
e.g.
public class Common<T>
where T: class
{
//... common fields here
public T Data {get;}
public Common(T data) => Data = data;
}
...
var area = new Common(new Area(){...});
//area.LoginId;
//area.Data.AreaId;
Related
I have the following scenario
Entity framework classes classes:
public class Block
{
public Guid Id { get; set; }
public ICollection<BlockLocation> BlockLocations { get; set; }
public BlockType Type { get; set; }
}
public class BlockLocation
{
public Guid Id { get; set; }
public Guid BlockId { get; set; }
public Block Block { get; set; }
}
And my Domain Entities look like
public class Block
{
public Block(BlockType type = BlockType.None) : this()
{
Type = type;
}
private Block() { }
public Guid Id { get; set; }
public List<BlockLocation> BlockLocations { get; set; }
public BlockType Type { get; set; }
}
public class LiveBlock : Block
{
public LiveBlock() : base(BlockType.Live) { }
}
public class UnsequencedBlock : Block
{
public UnsequencedBlock() : base(BlockType.Unsequenced) { }
}
public class BlockLocation
{
public Guid Id { get; set; }
public Guid BlockId { get; set; }
public Block Block { get; set; }
}
public enum BlockType
{
None = 0,
Live,
Unsequenced
}
And what I want to do is map from Entity Framework to a Domain entity to the child type and also preserve the reference so that I don't get a stack overflow
My mappings are
cfg.CreateMap<Data.Block, Domain.LiveBlock>();
cfg.CreateMap<Data.Block, Domain.UnsequencedBlock>();
cfg.CreateMap<Data.Block, Domain.Block>().PreserveReferences().ConstructUsing((block, context) =>
{
if (block.Type == BlockType.Live)
{
// This loops until stack overflow
return context.Mapper.Map<Domain.LiveBlock>(block);
}
if (block.Type == BlockType.Unsequenced)
{
return context.Mapper.Map<Domain.LiveBlock>(block);
}
return context.Mapper.Map<Domain.Block>(block);
});
cfg.CreateMap<Data.BlockLocation, Domain.BlockLocation>();
And I'm trying to do the following:
// This is the EF entity
var block = new Data.Block
{
Id = Guid.NewGuid(),
Type = BlockType.Live,
BlockLocations = new List<Data.BlockLocation>
{
new BlockLocation {Id = Guid.NewGuid()},
new BlockLocation {Id = Guid.NewGuid()}
}
};
block.BlockLocations[0].Block = block;
block.BlockLocations[1].Block = block;
// Trying to create a Domain entity
var domainBlock = Mapper.Map<Data.Block, Domain.Block>(block);
The result that I want to achieve is for domainBlock to be of type LiveBlock and have a list of BlockLocations which in turn have the same LiveBlock entity as their Block property
What I get is a loop in ConstructUsing, until I get stack overflow.
Now, my questions are:
Can this be achieved with AutoMapper?
If yes, can it be done with ContructUsing? I've also tried ConvertUsing, but I get the same result.
Some other approach maybe?
I know that a way of doing to would be to Ignore the BlockLocations property from Domain.Block and map them separately, but I would like to have Automapper to that automatically.
Thank you for your help.
Got it working with Lucian's help
I changed the mapper to the following
cfg.CreateMap<Data.Block, Domain.LiveBlock>().PreserveReferences();
cfg.CreateMap<Data.Block, Domain.UnsequencedBlock>().PreserveReferences();
cfg.CreateMap<Data.Block, Domain.Block>().PreserveReferences().ConstructUsing((block, context) =>
{
if (block.Type == BlockType.Live)
{
var b = new LiveBlock();
return context.Mapper.Map(block, b, context);
}
if (block.Type == BlockType.Unsequenced)
{
var unsequencedBlock = new UnsequencedBlock();
return context.Mapper.Map(block, unsequencedBlock, context);
}
return context.Mapper.Map<Domain.Block>(block);
});
cfg.CreateMap<Data.BlockLocation, Domain.BlockLocation>().PreserveReferences();
The secred was usint the Map method that takes the context as a parameter
context.Mapper.Map(block, unsequencedBlock, context);
I have four classes :
public class Customer
{
public string FirstName { get; set; }
public string LastName { get; set; }
public List<Product> Product { get; set; }
}
public class Product
{
public int ProductNumber { get; set; }
public string ProductColor { get; set; }
}
///////////////////////////////////////////////
public class Customer_
{
public string FirstName { get; set; }
public string LastName { get; set; }
public List<Article> Article { get; set; }
}
public class Article
{
public int ArticleNumber { get; set; }
public string ArticleColor { get; set; }
}
And one instance :
var Cus = new List<Customer>
{
new Customer()
{
FirstName = "FirstName1",
LastName = "LastName1",
Product = new List<Product>
{
new Product()
{
ProductColor = "ProductColor1",
ProductNumber = 11
}
}
},
new Customer()
{
FirstName = "FirstName2",
LastName = "LastName2",
Product = new List<Product>
{
new Product()
{
ProductColor = "ProductColor2",
ProductNumber = 12
}
}
}
};
I want to create a new object List<Customer_> with the value of my instance Cus. For example Customer.FirstName = Customer_.FirstName, Customer.Product.ProductColor = Customer_.Article.ArticleColor etc
What is the best way to do this easily, could one use a Dictionary?
Mapping can be accomplished through the use of an Interface.
Define an interface(s) which provide a mapping of logically named properties such as the common color properties you mention:
// Some entities have different named properties but can be joined
// using those properties. This interface shows a common color which
// when implemented will route the processing to a common shared property
// which reports and sets the associated color.
public interface IDefinedColor
{
string Color { get; set; }
}
If you have to create partial classes for Product and Article and have them adhere to said interfaces. Hint if using an entity mapper such as EF this is a great way to do such maping using partials. Implement implement the interface and hook up the commonality:
// Holds the common properties for future processing.
public partial class Product : IDefinedColor
{
public string Color
{
get { return ProductColor; }
set { ProductColor = value; }
}
}
Then work off of the IDefinedColor mapped implementations as needed.
By using interfaces one is letting all future developers know of the contract which specifies a business logic equality in the properties and it is not hidden in other joining classes.
You could create a mapper extension class
public static class MapperExtension
{
public Customer_ Convert(this Customer customer)
{
return new Customer_()
{
FirstName = customer.FirstName,
LastName = customer.LastName,
Article = customer.Product.Convert()
};
}
public static List<Article> Convert(this List<Product> products)
{
return products.Select(x=> new Article(){
ArticleNumber = x.ProductNumber,
ArticleColor = x.ProductColor
};
}
}
make sure you reference the proper namespace where you place the extension class.
Call the code like this
Where customers is a List filled from your code
List<Customer_> convertedCustomers_ = customers.Select(x=> x.Convert()).ToList();
It depends on the relationhip between those components but I would simply add constructor to Customer_ that accepts a Customer object. And then you invoke that do perform the conversion. e.g.
public class Article
{
public Article(Product source)
{
this.ArticleNumber = source.ProductNumber;
this.ArticleColor = source.ProductColor;
}
}
public class Customer_
{
public Customer_(Customer source)
{
this.FirstName = source.FirstName;
this.LastName = source.LastName;
this.Article = source.Product.Select(o => new Article(o)).ToList()
}
...
}
//and finally to convert the list you can do something like
//initial list
var Cus = new List<Customer>() { ... etc. }
/converted list
var Cus_ = Cus.Select(o => new Cusomter_(o)).ToList();
Edit: I see from your comment above that you actually have 100 properties to map. I can see this is a pain. But if you have complex transformations like Product to Article then I would still go the manual route as above so you can be completely clear about what is going on. Alternatively you could look to use inheritance to redesign your objects with common base classes or interfaces, that would probably make mapping easier.
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.
I set ServiceStack.Text.JsConfig.IncludePublicFields = true; in AppHost.Configure but public fields are still not deserializing in JSON format.
Here is a simplified example:
[DataContract(Name = "RspItems")]
public class RspItems<T1>
{
[DataMember]
public int ItemCount { get { return Items == null ? 0 : Items.Count; } set { } }
[DataMember]
public IList<T1> Items;
public void SetItems(T1 item)
{
if (item != null)
{
Items = new List<T1>(1);
Items.Add(item);
}
}
public void SetItems(IList<T1> items)
{
Items = items;
}
}
[DataContract(Name="UserInfo")]
public class UserInfo
{
[DataMember]
public int UserID;
[DataMember]
public string LoginName;
[DataMember]
public string FirstName;
[DataMember]
public string LastName;
[DataMember]
public string Comment;
}
public class UserInfoReq<T> : IReturn<RspItems<T>>
{
public int? UserID { get; set; }
}
[Route("/app/user/list", "GET")]
public class UserInfoGetReq : UserInfoReq<UserInfo> { }
public class UserList : Service
{
public RspItems<UserInfo> Get(UserInfoGetReq req)
{
RspItems<UserInfo> rsp = new RspItems<UserInfo>();
UserInfo u = new UserInfo();
u.UserID = 3418;
u.LoginName = "jsmith";
u.FirstName = "John";
u.LastName = "Smith";
u.Comment = req.UserID.HasValue ? req.UserID.ToString() : "NULL";
rsp.SetItems(u);
return rsp;
}
}
The above example does not deserialize the response object in JSON format, although it works in XML format.
But inexplicably, if I remove the DataContract attributes on the classes, JSON format works.
Is this a bug?
Also, in the request DTO above, if I make UserID a simple public field (instead of being a property), then it is not deserialized from the querystring. Why?
Why does ServiceStack not include public fields by default anyway? Aren't DTOs supposed to be just "flat" structures used as a container for serializing/deserializing inputs and outputs (ie: the simpler, the better)? Public fields are also smaller and faster (no generated hidden private fields and getter/setter functions).
Note: Please don't suggest to just turn all public fields into properties because there are already tons of serialization structures that exist in the project. With many coming from different teams.
I have a class
public class Offer
{
public Int32 OfferId { get; set; }
public string OfferTitle { get; set; }
public string OfferDescription { get; set; }
}
and another class
public class OfferLocationViewModel
{
public Offer Offer { get; set; }
public Int32 InTotalBranch { get; set; }
public Int32 BusinessTotalLocation { get; set; }
}
Now in my controller I have the following
public ActionResult PresentOffers(Guid id)
{
DateTime todaysDate=Utility.getCurrentDateTime();
var rOffers=(from k in dc.GetPresentOffers(id,todaysDate)
select new OfferLocationViewModel()
{
Offer. //I dont get anything here..
}).ToList();
return PartialView();
}
Now the problem is in my controller, I can not access any property of the 'Offer' class !!
I thought, since i am creating a new OfferLocationViewModel() and this has a property of type 'Offer', I will be able to access the properties..But I can not.
Can anyone give me some idea about how to do that?
In a class initializer like new OfferLocationViewModel { ... } you can only set the immediate properties, i.e. 'Offer = new Offer()'.
You can't access the contained type's properties through the initializer.
Though you can initialize the view model's Offer to a new Offer with the given properties like this:
var rOffers = (from k in dc.GetPresentOffers(id,todaysDate)
select new OfferLocationViewModel {
Offer = new Offer {
OfferId = ...,
OfferTitle = ...,
OfferDescription = ...
}
}).ToList();