AutoMapper Let Instance Variable - c#

Apologies if this has been asked before, I'm not sure of the specific terms to ask.
A short example:
public class SignOffDetails
{
public int fUserID {get; set;}
public DateTime SignedAt {get; set;}
}
public class User
{
public int UserID {get; set;}
public string FullName {get; set;}
public Image Signature {get; set;}
}
public class MdlsCombined
{
public int UserID {get; set;}
public string FullName {get; set;}
public Image Signature {get; set;}
}
public void Program
{
Mapper.CreateMap<SignOffDetails, MdlsCombined>()
.ForMember(m => m.UserID, y => y.MapFrom(z => z.fUserID));
// Awesome
}
I know I can just map them individually, but is there a function to do the following that I haven't yet discovered?
Mapper.CreateMap<SignOffDetails, MdlsCombined>()
.Let(z => (User)Users.GetUser(z.fUserID))
.ForMember(m => m.UserID, y => y.MapFrom(z => z.fUserID))
.ForMember(m => m.FullName, y => y.MapFromLet(l => ((User)l).FullName))
.ForMember(m => m.Signature, y => y.MapFromLet(l => ((User)l).Signature));
I realize this is quite silly and kinda removes the whole point of procedural programming in the first place, but it's still a legit use imho.
The actual solution is to have two maps from SignOffDetails > MdlsCombined and User > MdlsCombined, but that ain't fluent ;)

Related

Multiple DB tables for one property in model

I have the following classes:
public class Customer {
public virtual int Id {get; set;}
public virtual string Surname {get; set;}
public virtual string Prename {get; set;}
public virtual Location Location {get; set;}
}
public class Location {
public virtual int Id {get; set;}
public virtual string ZipCode {get; set;}
public virtual string Name {get; set;}
}
public class CustomLocation : Location {
}
And the following mapping:
public class CustomerMapping : ClassMapping<Customer> {
public CustomerMapping(){
Table("Customer");
Property(a => a.Surname, b =>
{
b.NotNullable(true);
});
Property(a => a.Prename, b =>
{
b.NotNullable(true);
});
ManyToOne(a => a.Location, b =>
{
b.Column($"FK_Location_Id");
});
}}
public class LocationMapping : ClassMapping<Location> {
public LocationMapping(){
Table("Location");
Property(a => a.ZipCode, b =>
{
b.NotNullable(true);
});
Property(a => a.Name, b =>
{
b.NotNullable(true);
});
}}
public class CustomLocationMapping : ClassMapping<CustomLocation>{
public CustomLocationMapping(){
Table("CustomLocation");
Property(a => a.ZipCode, b =>
{
b.NotNullable(true);
});
Property(a => a.Name, b =>
{
b.NotNullable(true);
});
}}
My target is that I have a Location table that is being updated automatically by a script and a CustomLocation table where the user can add locations if there are some missing (or outside the country).
My problem is, that I don't know how to properly map this to the Customer that it can be both Location or CustomLocation.
Any ideas? Thanks in advance.
You cannot map one property to two columns in two different tables. How would NHibernate know, which table to use? You would also lose the referential integrity for that column.
However, your goal can be achieved by using a slightly different approach: Instead of using two tables for the same structure, just use one Location-table with the following class representation:
public class Location
{
public virtual int Id { get; set; }
public virtual string ZipCode { get; set; }
public virtual string Name { get; set; }
public virtual bool IsSystem { get; set; } // just use a boolean column in the table for this one
}
Your script can insert / update / delete all the rows where IsSystem == true and ignore the rest. When the user adds an entry, just set IsSystem = false.

Automapper flattening of nested object child class

I am trying to perform the following operation with AutoMapper and don't get the expected result.
I have the following configuration:
public interface IFlatInterface
{
public string A {get; set;}
public string B {get; set;}
public string C {get; set;}
public bool D {get; set;}
}
public class ParentObject
{
public Data X {get; set;}
public Measure Y {get; set;}
}
public class Data
{
public string A {get; set;}
public string B {get; set;}
}
public class Measure
{
public string C {get; set;}
public bool D {get; set;}
}
I have defined the following mapping rules
cfg.CreateMap<IFlatInterface, ParentObject>()
.ForMember(p => p.Measure, o => o.MapFrom(f => f))
.ForMember(p => p.Data, o => o.MapFrom(f => f))
cfg.CreateMap<ParentObject, IFlatInterface>()
.ForMember(i => i.A, o => o.MapFrom(p => p.X.A))
.ForMember(i => i.B, o => o.MapFrom(p => p.X.B))
.ForAllOtherMembers(o => o.MapFrom(p.Y))
The issue is that the value which is populated is a string "p.Measure" for all the remaining fields. I would like to mapping to happen recursively on the members of Measure. I can't put a extensive rule because different classes can implement IFlatInterface.
Any idea on how to achieve this?
Thanks

Fluent NHibernate Mapping of Entity to Two Tables Joined by Non-Primary Key Column

I have the following entity and entity properties:
public class UserContact
{
public virtual ulong ContactId {get; set;}
public virtual ulong UserId {get; set;}
public virtual ulong ContactUserId {get; set;}
public virtual string ContactFirstNm {get; set;}
public virtual string ContactLastNm {get; set;}
}
My database schema contains the following view and table with columns:
CONTACT_VIEW
CONTACT_ID
USER_ID
CONTACT_USER_ID
USERS
USER_ID
FIRST_NM
LAST_NM
I am attempting to create my mapping class such that I can join the view and the table on CONTACT_VIEW.CONTACT_USER_ID to USERS.USER_ID. I do not know, however, how to do this join mapping.
public UserContactMap()
{
Table("CONTACT_VIEW");
CompositeId()
.KeyProperty(x => x.ContactId, "CONTACT_ID")
.KeyProperty(x => x.UserId, "USER_ID");
Map(x => x.ContactUserId, "CONTACT_USER_ID");
Join("USERS", jx =>
{
//what do i put here?
jx.Map(x => x.ContactFirstNm, "FIRST_NM");
jx.Map(x => x.ContactLastNm, "LAST_NM");
};
}
EDIT:
With modifications to my entity (and creating another entity), I was able to achieve the same effect of my original goal. However, I'm not convinced that there is not a way to do it similar to the way my mapping is laid-out above.
public class UserContact
{
public virtual ulong ContactId {get; set;}
public virtual ulong UserId {get; set;}
public virtual ulong ContactUserId {get; set;}
public virtual UserContactDetail ContactDetail {get; set;}
}
public class UserContactDetail
{
public virtual ulong UserId {get; set;}
public virtual string FirstNm {get; set;}
public virtual string LastNm {get; set;}
}
//map constructor
public UserContactMap()
{
Table("CONTACT_VIEW");
CompositeId()
.KeyProperty(x => x.ContactId, "CONTACT_ID")
.KeyProperty(x => x.UserId, "USER_ID");
Map(x => x.ContactUserId, "CONTACT_USER_ID");
References(x => x.ContactDetail , "CONTACT_USER_ID");
}
//map constructor
public ContactDetailMap()
{
Table("USERS");
Id(x => x.UserId, "USER_ID");
Map(x => x.FirstNm, "FIRST_NM");
Map(x => x.LastNm, "LAST_NM");
}
Does anyone know a more elegant solution (with just a join of two tables to create a single entity). I don't like the fact that I had to create another entity just to get my original entity "working."

Automapper mapping clarification to satisfy design

I am currently working with a DB table and I need to map extra properties from DAO to BE class.
I have to produce XML like the following:
<Zoos>
<Zoo>
<ZooId>234OI456<ZooId>
<Name>The Zoo</Name>
<Address>3456 Kramer</Address
<ZipCode></ZipCode>
<Animals>
<Animal Type="REPTILE">Cobra</Animal>
<Animals>
<Zoo>
<Zoos>
The extra columns in the db view are like so:
ANI_TYPE VARCHAR(20)
ANI_VALUE VARCHAR(20)
Previously when I didn't have the extra columns I mapped the values like this for each Zoo
Mapper.CreateMap<ZooDAO, ZooBE>()
.ForMember(d => d.ZooId, e => e.ZOO_ID))
.ForMember(d => d.Name, e => e.ZOO_NAME))
.ForMember(d => d.Address, e => e.ZOO_ADDRESS))
.ForMember(d => d.ZipCode, e => e.ZOO_ZIPCODE));
How would I go about mapping these 2 columns(ANI_TYPE, ANI_VALUE) so i can create the structure shown in the xml in regards to Animals?
I have a c# class for Animal type which has the following
public enum AnimalType
{
INVALID,
REPTILE,
MAMMAL,
INSECT
}
My C# class for the Animal looks like this but i guess it will require rework. Feel free to provide suggestions/examples:
Currently this is what my classes look like:
//BE class
public class Zoo
{
public int ZooId {get; set;}
public string Name { get; set; }
public string Address {get; set; }
public string ZipCode {get; set;}
public List<Animal> Animals {get; set;}
}
//BE Class
public class Animal
{
public string Type {get; set;}
public string Text { get; set; }
}
My DAO class
public class ZooDAO
{
public int ZOO_ID {get; set;}
public string ZOO_NAME { get; set; }
public string ZOO_ADDRESS {get; set; }
public string ZOO_ZIPCODE {get; set;}
public string ANI_TYPE {get; set;}
public string ANI_VALUE {get; set;}
}
I appreciate if someone can assist me with the above.
Thanks,

Can automapper handle a case where the some of the properties do not match?

Suppose I have a destination class and a source class that are mostly the same. Almost all of the properties map automatically using automapper.
Say that of the 30 properties on these classes, two don't have a direct corelation in any way that automapper can automatically figureout.
Is there a way to tell automapper to connect two properties manually?
For Example:
class DTOMyObject
{
public int Test {get; set;}
public int Test2 {get; set;}
public int Test3 {get; set;}
public int Test4 {get; set;}
public int Test5 {get; set;}
// Continues for many many more properties.
public int RandomOtherName {get; set;}
public int SecondRandomName {get; set;}
}
class ViewMyObject
{
public int Test {get; set;}
public int Test2 {get; set;}
public int Test3 {get; set;}
public int Test4 {get; set;}
public int Test5 {get; set;}
// Continues for many many more properties.
public int MapsToTheFirstRandomName {get; set;}
public int ShouldMapToTheRandomNameThatIsSecond {get; set;}
}
Since there are a high percentage of properties that can automatically map, I would like to use automapper. But the docs and videos I have read/watched do not show how to take care of the edge cases.
Is there a way to get these classes to automap? If so, please provide a code example?
Thanks
Mapper.CreateMap<DTOMyObject, ViewMyObject>()
.ForMember(dest => dest.MapsToTheFirstRandomName, opt => opt.MapFrom(src => src.RandomOtherName))
.ForMember(dest => dest.ShouldMapToTheRandomNameThatIsSecond , opt => opt.MapFrom(src => src.SecondRandomName));

Categories