How to use Automapper with Object in Object - c#

I want to Map two types of Objects but I didn't find the way to do it.
User class:
public partial class TUser
{
[Key]
[Column("id")]
public int Id { get; set; }
[Column("login")]
[StringLength(50)]
public string Login { get; set; }
[Column("password")]
[StringLength(50)]
public string Password { get; set; }
[Column("role")]
[StringLength(50)]
public string Role { get; set; }
[Column("isDeleted")]
public bool? IsDeleted { get; set; }
[Column("avatarUrl")]
[StringLength(50)]
public string AvatarUrl { get; set; }
[Column("iso")]
[StringLength(2)]
public string Iso { get; set; }
[Column("lastLogonDate", TypeName = "datetime")]
public DateTime? LastLogonDate { get; set; }
[Column("createdDate", TypeName = "datetime")]
public DateTime? CreatedDate { get; set; }
[Column("lastUpdatedDate", TypeName = "datetime")]
public DateTime? LastUpdatedDate { get; set; }
public byte[] PasswordHash { get; set; }
public byte[] PasswordSalt { get; set; }
[InverseProperty("IdNavigation")]
public virtual TWorker TWorker { get; set; }
}
UserForLogin Class:
public class UserForLogin
{
public int Id { get; set; }
public string Login { get; set; }
public string Role { get; set; }
public string AvatarUrl { get; set; }
public string Iso { get; set; }
public TWorker TWorker { get; set; }
}
TWorker class:
public partial class TWorker
{
public TWorker()
{
TWorkerToWorkType = new HashSet<TWorkerToWorkType>();
TrEventToWorker = new HashSet<TrEventToWorker>();
TrWorkerToWorkerCategory = new HashSet<TrWorkerToWorkerCategory>();
}
[Key]
[Column("id")]
public int Id { get; set; }
[Column("lastname")]
[StringLength(50)]
public string Lastname { get; set; }
[Column("firstname")]
[StringLength(50)]
public string Firstname { get; set; }
[Column("email")]
[StringLength(50)]
public string Email { get; set; }
[Column("phone")]
[StringLength(50)]
public string Phone { get; set; }
[Column("address")]
[StringLength(50)]
public string Address { get; set; }
[Column("postcode")]
[StringLength(50)]
public string Postcode { get; set; }
[Column("locality")]
[StringLength(50)]
public string Locality { get; set; }
[Column("workerCategoryKey")]
public int? WorkerCategoryKey { get; set; }
[Column("sexe")]
[StringLength(50)]
public string Sexe { get; set; }
[ForeignKey(nameof(Id))]
[InverseProperty(nameof(TUser.TWorker))]
public virtual TUser IdNavigation { get; set; }
[InverseProperty("WorkerKeyNavigation")]
public virtual ICollection<TWorkerToWorkType> TWorkerToWorkType { get; set; }
[InverseProperty("WorkerKeyNavigation")]
public virtual ICollection<TrEventToWorker> TrEventToWorker { get; set; }
[InverseProperty("WorkerKeyNavigation")]
public virtual ICollection<TrWorkerToWorkerCategory> TrWorkerToWorkerCategory { get; set; }
}
AutoMapperProfiles class:
public AutoMapperProfiles()
{
CreateMap<TUser, UserForLogin>()
.ForMember(
dest => dest.TWorker,
opt => opt.MapFrom(src => src.TWorker)
);
}
But TWorker is always null and I can't find what am I doing wrong?
If I use TUser only to return my object without Automapper code, TWorker contains the values I want.

You just need to implement the map for the subObject and autoMapper will handle it for you.
To be precise, if you map a property to another property which has a different type, autoMapper will try to find a corresponding map.

Related

AutoMapperMappingException: Missing type map configuration or unsupported mapping

I'm attempting to use AutoMapper for the first time. The GSMSite maps fine, but I get an error when trying to map the GSMUnit:
AutoMapperMappingException: Missing type map configuration or unsupported mapping.
Do I need to specify a relationship between GSMSite and GSMUnits?
Domain class:
public class ApplicationUser : IdentityUser
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Company { get; set; }
public string Telephone { get; set; }
public bool PasswordReset { get; set; } = false;
public virtual ICollection<GSMSite> GSMSites { get; set; }
}
public class GSMSite
{
public int Id { get; set; }
public string SiteName { get; set; }
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string Town { get; set; }
public string Postcode { get; set; }
public string ContactName { get; set; }
public string ContactNumber { get; set; }
public string ContactEmail { get; set; }
public string ApplicationUserId { get; set; }
public virtual ApplicationUser ApplicationUser { get; set; }
public virtual ICollection<GSMUnit> GSMUnits { get; set; }
}
public class GSMUnit
{
public int Id { get; set; }
public string Model { get; set; }
public string Firmware { get; set; }
public string TelephoneNum { get; set; }
public int GSMSiteId { get; set; }
public virtual GSMSite GSMSite { get; set; }
}
Contract class:
public class GSMResponse
{
public int Id { get; set; }
public string Model { get; set; }
public string Firmware { get; set; }
public string TelephoneNum { get; set; }
}
public class SiteResponse
{
public int Id { get; set; }
public string SiteName { get; set; }
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string Town { get; set; }
public string Postcode { get; set; }
public string ContactName { get; set; }
public string ContactNumber { get; set; }
public string ContactEmail { get; set; }
}
Mapping:
public DomainToResponseProfile()
{
CreateMap<GSMSite, SiteResponse>();
CreateMap<GSMUnit, GSMResponse>();
}

Invalid column name: "ColumnName#" with a suffix number

I have a table Users:
I am using Entity Framework 6 to make the type configuration
public class UsersMapping : EntityTypeConfiguration<Users>
{
public UsersMapping()
{
HasKey(t => t.UserID);
Property(t => t.UserID).IsRequired();
ToTable("Users", "dbo");
Property(t => t.Id).HasColumnName("UserID");
}
}
and this is the Users class:
public class Users : EntityBase
{
public int UserID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string UserName { get; set; }
public DateTime DateCreated { get; set; }
public byte[] Timestamp { get; set; }
public byte[] Password { get; set; }
public DateTime? DateActivated { get; set; }
public bool LockedOut { get; set; }
public string Address { get; set; }
public string City { get; set; }
public int? State { get; set; }
public string Zip { get; set; }
public string SecurityQuestion { get; set; }
public string SecurityAnswer { get; set; }
public string Email { get; set; }
public string PhoneNumber { get; set; }
public bool? ReportServiceAccount { get; set; }
public string CompanyName { get; set; }
public int? ILAC { get; set; }
public string BioFingerprint { get; set; }
public string Title { get; set; }
public string Squad { get; set; }
public byte[] SignatureFile { get; set; }
public byte? CETGroupID { get; set; }
public string TokenID { get; set; }
public int? Pin { get; set; }
public string RadioNr { get; set; }
}
public class EntityBase
{
public int Id { get; set; }
}
I am trying to set the Id field as primary because my repository pattern works using the field Id that is not present on this case in the table. But when I am trying to get the set of users I get this error:
The column name is invalid UserID1
The weird thing to me is the #1 that is at the end. What I am doing wrong?

Entity Framework - Update action and Automapper

For example, I have the following infrastructure class:
[Table("GeoHistory")]
public partial class GeoHistory
{
public int Id { get; set; }
public int CompanyId { get; set; }
public int DriverId { get; set; }
[StringLength(50)]
public string Name { get; set; }
public string Description { get; set; }
[StringLength(100)]
public string GeofenceLocation { get; set; }
[StringLength(100)]
public string GeofencePrevious { get; set; }
[StringLength(20)]
public string StateLocation { get; set; }
[StringLength(20)]
public string StatePrevious { get; set; }
public DateTime? DateTime { get; set; }
[StringLength(5)]
public string Heading { get; set; }
public decimal? Speed { get; set; }
[StringLength(50)]
public string Status { get; set; }
}
and the following View class (let's forget about domain layer):
public class GeoHistoryViewModel
{
public int Id { get; set; }
public int? CompanyId { get; set; }
public int? DriverId { get; set; }
[StringLength(50)]
public string Name { get; set; }
public string Description { get; set; }
}
as we can see, we edit only part of field list.
Now, we want to update data in DB. Of course, we can write like:
Infrastructure.Main.GeoHistory geoHistory = db.GeoHistories.Find(id);
geoHistory.CompanyId = model.CompanyId;
geoHistory.DriverId = model.DriverId;
geoHistory.Name = model.Name;
........
db.SaveChanges();
It works. But I want to use Automapper. And if I try to do the following:
Infrastructure.Main.GeoHistory geoHistory = mapper.Map<Infrastructure.Main.GeoHistory>(model);
db.GeoHistories.Attach(geoHistory);
db.Entry(geoHistory).State = EntityState.Modified;
db.SaveChanges();
It works, but of course remove values of fields, which are not exist in View Model, but exist in infrastructure class. How to use automapper, but don't lost these fields?

C# Entity Framework - Multiple relationships

I'm not sure if this is possible or not, but I thought I would ask...
I have two database tables. One is a list of users pulled from Active Directory. The second table is a list of scheduled forwards. The relationship I would like to create would be...
public class AdObject
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string ObjectType { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string DisplayName { get; set; }
public string DistinguishedName { get; set; }
public string PrimaryEmail { get; set; }
public string Alias { get; set; }
public string SamAccountName { get; set; }
public string PrimaryDisplay { get; set; }
public string CanonicalName { get; set; }
public string OU { get; set; }
public string CoreGroup { get; set; }
public string ForwardedTo { get; set; }
public bool? IsDisabled { get; set; }
public bool? IsForwarded { get; set; }
public bool? DeliverAndRedirect { get; set; }
public bool? DisableForwardAtLogon { get; set; }
public DateTime? DisableAtLogonAfter { get; set; }
public string Notify { get; set; }
public DateTime? LastLogon { get; set; }
public DateTime? LastApiLogon { get; set; }
public DateTime? LastCheck { get; set; }
// This isn't required. But if possible I would like this to be
// a relationship to another AdObject whos "PrimaryEmail" matches
// the "ForwardedTo" column of this AdObject. There will not always
// be a match though, so not too important just wondering if its possible.
public AdObject ForwardedToObject { get; set; }
// This would be a list of forwards where the "ForwardFrom"
// column matches the "PrimaryEmail" of this AdObject.
public ICollection<Forward> ScheduledForwards { get; set; }
= new List<Forward>();
// FYI... Technically ID,SamAccountName,PrimaryEmail,DistinguishedName,
// and CanonicalName are all unique. They could all be keys.
}
public class Forward
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string ForwardFrom { get; set; }
public string ForwardTo { get; set; }
public bool? DeliverAndRedirect { get; set; }
public DateTime? StartTime { get; set; }
public DateTime? StopTime { get; set; }
public string Recurrence { get; set; }
public bool? DisableForwardAtLogon { get; set; }
public DateTime? DisableAtLogonAfter { get; set; }
public string Notify { get; set; }
public string StartJobId { get; set; }
public string StopJobId { get; set; }
public string StartJobStatus { get; set; }
public string StopJobStatus { get; set; }
public DateTime? StartJobCompleted { get; set; }
public DateTime? StopJobCompleted { get; set; }
public DateTime? StartJobCreated { get; set; }
public DateTime? StopJobCreated { get; set; }
public string StartReason { get; set; }
public string StopReason { get; set; }
// This would be the AdObject whos "PrimaryEmail" matches the
// "ForwardTo" column.
public AdObject ForwardToObject { get; set; }
// This would be the AdObject whos "PrimaryEmail" matches the
// "ForwardFrom" column.
public AdObject ForwardFromObject { get; set; }
}
I think I got it figured out. I was having a hell of a time understanding the logic behind relationships. I had a few misconceptions that I ironed out and after going through every YouTube video, PluralSight Course and Udemy course I could find it finally started to click. I usually don't have this much trouble teaching myself these things, but the misconceptions I had were pointing me in the wrong direction. In the end I only had to specify the keys and two relationships (conventions did the rest).
public class AdObject
{
[Key, Column(Order = 0)]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string ObjectType { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string DisplayName { get; set; }
public string DistinguishedName { get; set; }
[Key, Column(Order = 1)]
public string PrimaryEmail { get; set; }
public string Alias { get; set; }
public string SamAccountName { get; set; }
public string PrimaryDisplay { get; set; }
public string CanonicalName { get; set; }
public string OU { get; set; }
public string CoreGroup { get; set; }
public bool? IsDisabled { get; set; }
public bool? IsForwarded { get; set; }
public bool? DeliverAndRedirect { get; set; }
public bool? DisableForwardAtLogon { get; set; }
public DateTime? DisableAtLogonAfter { get; set; }
public string Notify { get; set; }
public DateTime? LastLogon { get; set; }
public DateTime? LastApiLogon { get; set; }
public DateTime? LastCheck { get; set; }
public AdObject ForwardedToObject { get; set; }
public ICollection<Forward> ForwardRecipientSchedule { get; set; }
= new List<Forward>();
public ICollection<Forward> ForwardSchedule { get; set; }
= new List<Forward>();
}
public class Forward
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public AdObject ForwardFromObject { get; set; }
public AdObject ForwardToObject { get; set; }
public bool? DeliverAndRedirect { get; set; }
public DateTime? StartTime { get; set; }
public DateTime? StopTime { get; set; }
public string Recurrence { get; set; }
public bool? DisableForwardAtLogon { get; set; }
public DateTime? DisableAtLogonAfter { get; set; }
public string Notify { get; set; }
public string StartJobId { get; set; }
public string StopJobId { get; set; }
public string StartJobStatus { get; set; }
public string StopJobStatus { get; set; }
public DateTime? StartJobCompleted { get; set; }
public DateTime? StopJobCompleted { get; set; }
public DateTime? StartJobCreated { get; set; }
public DateTime? StopJobCreated { get; set; }
public string StartReason { get; set; }
public string StopReason { get; set; }
}
public class EntityContext : DbContext
{
public EntityContext() : base("name=EnityContext"){
}
public DbSet<AdObject> AdObjects { get; set; }
public DbSet<Forward> Forwards { get; set; }
//protected override void OnConfiguring(DbContext)
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<AdObject>()
.HasMany(f => f.ForwardSchedule)
.WithRequired(f => f.ForwardFromObject)
.WillCascadeOnDelete(false);
modelBuilder.Entity<AdObject>()
.HasMany(f => f.ForwardRecipientSchedule)
.WithRequired(f => f.ForwardToObject)
.WillCascadeOnDelete(false);
base.OnModelCreating(modelBuilder);
}
}

AutoMapper "Member not found" with UseDestinationValue

I am trying to use AutoMapper to map a ViewModel to a Model.
Here is my simplified ViewModel (the source) class:
public class EditPaypointVM
{
public Int64 Id { get; set; }
public Int64 OrganisationId { get; set; }
[Required]
public string OrganisationContactNumber { get; set; }
public Int64 PostalAddressId { get; set; }
public string PostalAddressAddressText { get; set; }
[Required]
public Int64 PostalAddressArea { get; set; }
public string PostalAddressAreaText { get; set; }
public string PostalAddressCode { get; set; }
public Int64 PhysicalAddressId { get; set; }
public string PhysicalAddressAddressText { get; set; }
[Required]
public Int64 PhysicalAddressArea { get; set; }
public string PhysicalAddressAreaText { get; set; }
public string PhysicalAddressCode { get; set; }
}
Here is my simplified Model (destination) class:
public class Paypoint
{
public Int64 Id { get; set; }
public virtual Organisation Organisation { get; set; }
public virtual Employer Employer { get; set; }
public virtual List<EmploymentContract> EmploymentContracts { get; set; }
public bool IsActive { get; set; }
}
public class Organisation
{
public Int64 Id { get; set; }
public virtual List<EmailAddress> EmailAdresses { get; set; }
public virtual List<ContactNumber> ContactNumbers { get; set; }
public virtual List<Address> Adresses { get; set; }
public string RegisteredName { get; set; }
public string TradingName { get; set; }
public string RegistrationNumber { get; set; }
public string WebsiteAddress { get; set; }
}
Here is the code I execute to create mappings in memory on application start:
Mapper.CreateMap<EditPaypointVM, Paypoint>()
.ForMember(dest => dest.IsActive,
opt => opt.UseValue(true))
.ForMember(dest => dest.Organisation,
opt => opt.UseDestinationValue())
.Ignore(i => i.Employer)
.Ignore(i => i.EmploymentContracts);
Upon executing 'AssertConfigurationIsvalid' within a unit test, an "Unmapped error is thrown which states that the Organisation member of Paypoint is unmapped.
Any ideas on what causes this?

Categories