Automapper maps source to destination but dest values are always null - entity-framework

I'm new to automapper and I'm having a problem with it. In this case the automapper is used to map models(EntityFramework generated) to my own viewmodels. This is what happens, the sourcemodel with it's values is mapped to a destinationmodel but the dest values are always null. What's going on with the values?
Now what did I do:
I referenced the automapper to my project and bootstrapped the mappings.
public static void RegisterAutoMapperMappings()
{
Mapper.Initialize(x =>
{
// Add the mappingprofiles you configured below
x.AddProfile(new RegistrationViewModelProfile());
});
}
public static IMappingExpression<TSource, TDest> IgnoreAllUnmapped<TSource, TDest>(this IMappingExpression<TSource, TDest> expression)
{
expression.ForAllMembers(opt => opt.Ignore());
return expression;
}
public class RegistrationViewModelProfile : Profile
{
protected override void Configure()
{
CreateMap<RegistrationViewModel, contact>().IgnoreAllUnmapped();
CreateMap<contact, RegistrationViewModel>().IgnoreAllUnmapped();
CreateMap<RegistrationViewModel, emailaddress>().IgnoreAllUnmapped();
CreateMap<emailaddress, RegistrationViewModel>().IgnoreAllUnmapped();
CreateMap<RegistrationViewModel, password>().IgnoreAllUnmapped();
CreateMap<password, RegistrationViewModel>().IgnoreAllUnmapped();
//Always check if mapping is valid
Mapper.AssertConfigurationIsValid();
}
}
My viewmodel:
public class RegistrationViewModel
{
public HttpPostedFileBase file { get; set; }
public String EmailAddress { get; set; }
public String Password { get; set; }
public string contact_givenname { get; set; }
public string contact_surname_prefix { get; set; }
public string contact_surname { get; set; }
public string contact_gender { get; set; }
public string contact_country { get; set; }
public string contact_residence { get; set; }
public Nullable<DateTime> contact_birth_date{ get; set; }
public DateTime create_date { get; set; }
public ICollection<int> Contact_roles { get; set; }
public string Emailaddress_verificationkey { get; set; }
}
My model:
public partial class contact
{
public contact()
{
this.contact_connection_rel = new HashSet<contact_connection_rel>();
this.contact_emailaddress_password_rel = new HashSet<contact_emailaddress_password_rel>();
this.contact_emailaddress_rel = new HashSet<contact_emailaddress_rel>();
this.contact_service_role_rel = new HashSet<contact_service_role_rel>();
this.given_answer = new HashSet<given_answer>();
this.given_answer1 = new HashSet<given_answer>();
}
public int contact_id { get; set; }
public string contact_initials { get; set; }
public string contact_givenname { get; set; }
public string contact_surname_prefix { get; set; }
public string contact_surname { get; set; }
public string contact_nickname { get; set; }
public string contact_gender { get; set; }
public Nullable<System.DateTime> contact_birth_date { get; set; }
public string contact_country { get; set; }
public string contact_residence { get; set; }
public string contact_ssn { get; set; }
public Nullable<System.DateTime> create_date { get; set; }
public Nullable<System.DateTime> modify_date { get; set; }
public Nullable<System.DateTime> delete_date { get; set; }
public virtual ICollection<contact_connection_rel> contact_connection_rel { get; set; }
public virtual ICollection<contact_emailaddress_password_rel> contact_emailaddress_password_rel { get; set; }
public virtual ICollection<contact_emailaddress_rel> contact_emailaddress_rel { get; set; }
public virtual ICollection<contact_service_role_rel> contact_service_role_rel { get; set; }
public virtual ICollection<given_answer> given_answer { get; set; }
public virtual ICollection<given_answer> given_answer1 { get; set; }
}
And to test the configuration the following lines are used. The vars contain the destination objects but are always null:
contact c = new contact();
contact testC = unitOfWork.ContactRepository.Find(82);
var x = Mapper.Map<contact, RegistrationViewModel>(testC);
var y = Mapper.Map(regModel, c, typeof(RegistrationViewModel), typeof(contact));
var b = Mapper.DynamicMap<RegistrationViewModel, contact>(regModel);
var z = Mapper.Map<RegistrationViewModel, contact>(regModel, c);
var w = Mapper.Map<RegistrationViewModel, contact>(regModel);

expression.ForAllMembers(opt => opt.Ignore());
You're telling AutoMapper to ignore all properties, so nothing gets mapped.
If you just want to ignore non-matching properties, see this answer for one way, otherwise you're going to have to explicitly map each property between the objects.

Related

Could not find the implementation of the query pattern for source type. Join not found

I don't know if I am doing this right. I have 2 tables Property and PropertyTypes. Each Property has 1 PropertyType. I am using a foreign key constraint. But on the creation of the controller, I get this error already:
"Could not find an implementation of the query pattern for source type 'DbSet'.'Join not found'
Please see my code below:
[Table("Property.Property")]
public class Property
{
[Key]
public int PropertyId { get; set; }
[StringLength(50)]
public string PropertyName { get; set; }
public int? Owner { get; set; }
public string Cluster { get; set; }
public string PropertyNumber { get; set; }
public string RegionCode { get; set; }
public string ProvinceCode { get; set; }
public string MunicipalCode { get; set; }
public string BarangayCode { get; set; }
public DateTime? DateAdded { get; set; }
public DateTime? DateModified { get; set; }
public int PropertyTypeId { get; set; }
public PropertyType PropertyType { get; set; }
[NotMapped]
public string Type { get; set; }
}
[Table("Property.Types")]
public class PropertyType
{
[Key]
public int PropertyTypeId { get; set; }
[StringLength(50)]
public string Type { get; set; }
public DateTime? DateAdded { get; set; }
public DateTime? DateModified { get; set; }
public List<Property> Properties { get; set; }
}
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false) {}
// DB Sets
public DbSet<Property> Properties { get; set; }
public DbSet<PropertyType> PropertyTypes { get; set; }
}
Controller
public class PropertyController : ApiController
{
[HttpGet]
[Authorize]
[Route("api/getproperties")]
public async Task<List<Property>> GetProperties()
{
using(var db = new ApplicationDbContext())
{
var properties = await (from p in db.Properties
join pt in db.PropertyTypes
on p.PropertyTypeId equals pt.PropertyTypeId
select new
{
PropertyId = p.PropertyId,
PropertyName = p.PropertyName,
Owner = p.ProertyOwner,
Cluster = p.Cluster,
PropertyNumber = p.PropertyNumber,
RegionCode = p.RegionCode,
ProvinceCode = p.ProvinceCode,
MunicipalCode = p.MunicipalCode,
BarangayCode = p.BarangayCode,
DateAdded = p.DateAdded,
DateModified = p.DateModified,
PropertyTypeId = p.PropertyTypeId,
type = pt.Type
}
).ToListAsync();
return properties;
}
}
}
Can you please show me the right way to do this? Thank you.

Returning Entity with its children

Hi I am trying to return all vehicles with their recorded mileage through an api using ASP.Net Core with the following code:
// GET: api/values
[HttpGet]
public IEnumerable<Vehicle> Get()
{
return _context.Vehicles.Include(m=>m.Mileages).ToList();
}
However this only returns the first vehicle with its mileages and not the others (there are five dummy vehicles in the db all with an initial mileage).
If I change the code to:
// GET: api/values
[HttpGet]
public IEnumerable<Vehicle> Get()
{
return _context.Vehicles.ToList();
}
it returns the full list of vehicles but no mileage.
My class files are:
public class Vehicle
{
public Vehicle()
{
Mileages = new List<Mileage>();
}
public int Id { get; set; }
public string Registration { get; set; }
public string Make { get; set; }
public string Model { get; set; }
public Marked Marked { get; set; }
public ICollection<Mileage> Mileages { get; set; }
}
and
public class Mileage
{
public int Id { get; set; }
public DateTime MileageDate { get; set; }
public string RecordedMileage { get; set; }
//Navigation Properties
public int VehicleId { get; set; }
public Vehicle Vehicle { get; set; }
}
thanks for looking!
Tuppers
you can have them auto-load (lazy loading) using proxies... but for that, your foreign entities and collections must be marked virtual in your POCOs:
public class Mileage
{
public int Id { get; set; }
public DateTime MileageDate { get; set; }
public string RecordedMileage { get; set; }
//Navigation Properties
public int VehicleId { get; set; }
public virtual Vehicle Vehicle { get; set; }
}
public class Vehicle
{
public Vehicle()
{
Mileages = new List<Mileage>();
}
public int Id { get; set; }
public string Registration { get; set; }
public string Make { get; set; }
public string Model { get; set; }
public Marked Marked { get; set; }
public virtual ICollection<Mileage> Mileages { get; set; }
}
The proxy creation and lazy loading turned on, but that's the default in EF6.
https://msdn.microsoft.com/en-us/data/jj574232.aspx
Let me know if this works.
Well after a lot of searching I managed to find a solution. I used the following:
[HttpGet]
public IEnumerable<VehicleDto> Get()
{
var query = _context.Vehicles.Select(v => new VehicleDto
{
Registration = v.Registration,
Make = v.Make,
Model = v.Model,
Marked = v.Marked,
Mileages = v.Mileages.Select(m => new MileageDto
{
MileageDate = m.MileageDate,
RecordedMileage = m.RecordedMileage
})
.ToList(),
})
.ToList();
return (IEnumerable<VehicleDto>) query.AsEnumerable();
this doesn't seem to be the most elegant way of doing this, if anyone could offer any advice but it does return what is required.
The DTO's look like:
public class VehicleDto
{
public string Registration { get; set; }
public string Make { get; set; }
public string Model { get; set; }
public Marked Marked { get; set; }
public ICollection<MileageDto> Mileages { get; set; }
}
and
public class MileageDto
{
public DateTime MileageDate { get; set; }
public string RecordedMileage { get; set; }
}
Thanks for taking the time to look at this
Tuppers

Entity framework navigation property is null

I have two models using Entity Framework.
public class Player
{
public int PlayerId { get; set; }
public string Name { get; set; }
public string Sex { get; set; }
public string Plays { get; set; }
public string FavouriteSurface { get; set; }
}
public class SinglesMatch
{
public int SinglesMatchId { get; set; }
public int Player1Id { get; set; }
public int Player2Id { get; set; }
public int PlayerIdWinner { get; set; }
public DateTime Date { get; set; }
public string Venue { get; set; }
public string Score { get; set; }
public List<Player> Players { get; set; }
}
I am using the below code to attempt to display the Name of the player, based on the PlayerId in the SinglesMatch model matching the PlayerID from the Player model.
#foreach (var item in #Model)
{
<ul id="Players" class="bg-success"></ul>
<br/>
<h3>Date - #Html.DisplayFor(#modelItem => item.Date)</h3>
<li>Venue - #Html.DisplayFor(#modelItem => item.Venue)</li>
<li>Player 1 - #Html.DisplayFor(#modelItem => item.Players.First(p => p.PlayerId == item.Player1Id).Name)</li>
<li>Player 2 - #Html.DisplayFor(#modelItem => item.Players.First(p => p.PlayerId == item.Player2Id).Name)</li>
<li>Score- #Html.DisplayFor(#modelItem => item.Score)</li>
}
Upon debugging, the navigation property is always showing as null when the model is retrieved from my repository.
Am I using the navigation property in the correct fashion ? is there a problem with my query ?
Edit to include DbContext:
public TennisTrackerContext() : base("name=TennisTrackerContext")
{
}
public DbSet<Player> Players { get; set; }
public DbSet<PlayerRecord> PlayerRecords { get; set; }
public DbSet<SinglesMatch> SinglesMatches { get; set; }
public DbSet<DoublesMatch> DoublesMatches { get; set; }
public DbSet<Venue> Venues { get; set; }
}
}
You need to add a bridge table. Sql will create this automatically but you won't have access to the variables unless you create it in c#.
public class Player
{
public int PlayerId { get; set; }
public string Name { get; set; }
public string Sex { get; set; }
public string Plays { get; set; }
public string FavouriteSurface { get; set; }
List<PlayerInMatch> Matches { get; set; }
public Player()
{
Matches = new List<PlayerInMatch>();
}
}
public class PlayerInMatch
{
public int Id { get; set; }
public int PlayerId { get; set; }
[ForeignKey("PlayerId")]
public Player Player { get; set; }
public int SinglesMatchId { get; set; }
[ForeignKey("SinglesMatchId")]
public SinglesMatch SinglesMatch { get; set; }
}
public class SinglesMatch
{
public int SinglesMatchId { get; set; }
public int PlayerIdWinner { get; set; }
public DateTime Date { get; set; }
public string Venue { get; set; }
public string Score { get; set; }
public List<PlayerInMatch> Players { get; set; }
public SinglesMatch()
{
Players = new List<PlayerInMatch>();
}
}
static void Main(string[] args)
{
var match = new SinglesMatch();
match.Players.Select(c => c.Player.Name);
}
You need to make your navigation property virtual to enable lazy/eager loading:
public class SinglesMatch
{
public int SinglesMatchId { get; set; }
public int Player1Id { get; set; }
public int Player2Id { get; set; }
public int PlayerIdWinner { get; set; }
public DateTime Date { get; set; }
public string Venue { get; set; }
public string Score { get; set; }
public virtual List<Player> Players { get; set; }
}
Also, did you define the relationship between SinglesMatch and Singles in fluent api?
EDIT: I see you don't have any relations mapped through annotations or fluent api whatsoever, I suggest you take a look at this:
https://msdn.microsoft.com/en-us/data/jj591617.aspx

Getting ObjectContext error even after calling ToList

When calling the method directly below I get a ObjectDisposedException when calling Mapper.Map with the retrieved list.
System.ObjectDisposedException: The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.
public IEnumerable<Models.Provider> Get(string owner)
{
List<Data.Models.Provider> providers;
using (var db = new Data.ProviderDirectoryContext())
{
providers = db.Providers.Where(p => p.Owner.Name == owner).ToList();
}
var dtoProviders = Mapper.Map<List<Data.Models.Provider>, List<Models.Provider>>(providers);
return dtoProviders;
}
I previously had the code like this (below), I wasn't getting an error, but the database was getting pounded when doing the mapping, and it was taking too long. I don't want to hit the database, when doing the mapping.
public IEnumerable<Models.Provider> Get(string owner)
{
using (var db = new Data.ProviderDirectoryContext())
{
var providers = db.Providers.Where(p => p.Owner.Name == owner).ToList();
var dtoProviders = Mapper.Map<List<Data.Models.Provider>, List<Models.Provider>>(providers);
return dtoProviders;
}
}
How can I retrieve all the data before doing the mapping?
Here is the DbContext and the Data.Models.Provider for your reference.
public class ProviderDirectoryContext : DbContext
{
public DbSet<Owner> Owners { get; set; }
public DbSet<Location> Locations { get; set; }
public DbSet<LocationAuditLog> LocationAuditLog { get; set; }
public DbSet<Office> Offices { get; set; }
public DbSet<OfficePhoneNumber> OfficePhoneNumbers { get; set; }
public DbSet<OfficeAuditLog> OfficeAuditLog { get; set; }
public DbSet<OfficeDay> OfficeDays { get; set; }
public DbSet<Provider> Providers { get; set; }
public DbSet<ProviderPhoneNumber> ProviderPhoneNumbers { get; set; }
public DbSet<ProviderAuditLog> ProviderAuditLog { get; set; }
public DbSet<ProviderType> ProviderTypes { get; set; }
public DbSet<ProviderSpecialty> ProviderSpecialties { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Entity<Provider>().HasRequired(cn => cn.Owner).WithMany().WillCascadeOnDelete(false);
modelBuilder.Entity<Office>().HasRequired(cn => cn.Owner).WithMany().WillCascadeOnDelete(false);
}
}
public class Provider
{
public int Id { get; set; }
public int OwnerId { get; set; }
public virtual Owner Owner { get; set; }
public int? ProviderTypeId { get; set; }
public virtual ProviderType ProviderType { get; set; }
public int? ProviderSpecialtyId { get; set; }
public virtual ProviderSpecialty ProviderSpecialty { get; set; }
[Required]
[StringLength(75)]
public string FirstName { get; set; }
[StringLength(75)]
public string MiddleName { get; set; }
[Required]
[StringLength(75)]
public string LastName { get; set; }
[StringLength(100)]
public string EmailAddress { get; set; }
public virtual ICollection<ProviderPhoneNumber> PhoneNumbers { get; set; }
public string Note { get; set; }
public DateTime? InactiveOn { get; set; }
public int OfficeId { get; set; }
public virtual Office Office { get; set; }
public virtual ICollection<ProviderAuditLog> AuditLog { get; set; }
[Required]
public DateTime CreatedOn { get; set; }
[Required]
[StringLength(75)]
public string CreatedBy { get; set; }
[Required]
public DateTime ModifiedOn { get; set; }
[Required]
[StringLength(75)]
public string ModifiedBy { get; set; }
}
Thanks for the help!
The problem is that the Models.Provider class contains other classes like Models.Office, and Models.PhoneNumbers that were not eagerly loaded by the query. In addition to that, the Models.Provider class needs to be flattened. The Mapper wants to recursively map everything, and it keeps going down to the next class. For example, Provider.Office.Location.Offices.
The solution is to flatten Models.Provider and add .Include() to the query so it eagerly loads the data required.
I'll clean this up a bit more, but this is currently working.
public IEnumerable<Models.Provider> Get(string owner)
{
List<Data.Models.Provider> providers;
using (var db = new Data.ProviderDirectoryContext())
{
providers = db.Providers
.Where(p => p.Owner.Name == owner)
.Include("ProviderType")
.Include("ProviderSpecialty")
.Include("Office")
.Include("PhoneNumbers")
.ToList();
}
var dtoProviders = Mapper.Map<List<Data.Models.Provider>, List<Models.Provider>>(providers);
return dtoProviders;
}
public class Provider
{
public int Id { get; set; }
public int OwnerId { get; set; }
public int OfficeId { get; set; }
public string OfficeName { get; set; }
public int? ProviderTypeId { get; set; }
public string ProviderTypeName { get; set; }
public int? ProviderSpecialtyId { get; set; }
public string ProviderSpecialtyName { get; set; }
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public string EmailAddress { get; set; }
public virtual ICollection<PhoneNumber> PhoneNumbers { get; set; }
public string Note { get; set; }
public DateTime? InactiveOn { get; set; }
public DateTime CreatedOn { get; set; }
public string CreatedBy { get; set; }
public DateTime ModifiedOn { get; set; }
public string ModifiedBy { get; set; }
}
I am not sure how much this will help with performance but declaring the variable you don't want to dispose outside the using statement should fix your dispose exception.
public IEnumerable<Models.Provider> Get(string owner)
{
IEnumerable<Models.Provider> dtoProviders;
using (var db = new Data.ProviderDirectoryContext())
{
List<Data.Models.Provider> providers = db.Providers.Where(p => p.Owner.Name == owner).ToList();
dtoProviders = Mapper.Map<List<Data.Models.Provider>, List<Models.Provider>>(providers);
}
return dtoProviders;
}

EF code first property not mapped

The problem I'm encountering is when I try to insert a new record in a ASPxGridView which is a master of detail in an asp.net page.
This only occurs when adding a new record is required when there is no record.
EnderecoEscola entity:
namespace DAL
{
[Table("CAD_ENDERECO_ESCOLA")]
public class EnderecoEscola
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ENDESC_ID { get; set; }
[Required]
public int ESCOLA_ID { get; set; }
[Association("Escolas", "ESCOLA_ID", "ESCOLA_ID")]
[ForeignKey("ESCOLA_ID")]
public virtual Escola Escola { get; set; }
[Required]
public int TPOEND_ID { get; set; }
[ForeignKey("TPOEND_ID")]
public virtual TipoEndereco TipoEndereco { get; set; }
[Required]
public int ENDESC_UF_ID { get; set; }
[ForeignKey("ENDESC_UF_ID")]
public virtual UnidadeFederativa UnidadeFederativa { get; set; }
[Required]
public int ENDESC_MUN_iD { get; set; }
[ForeignKey("ENDESC_MUN_iD")]
public virtual Municipio Municipio { get; set; }
[StringLength(10), Required]
[MinLength(8)]
public string ENDESC_CEP { get; set; }
[StringLength(100), Required]
[MinLength(10)]
public string ENDESC_ENDERECO { get; set; }
[StringLength(15)]
public string ENDESC_NRO { get; set; }
[StringLength(25)]
public string ENDESC_COMPL { get; set; }
[StringLength(70)]
public string ENDESC_BAIRRO { get; set; }
[NotMapped]
public String TPEND_DESCRICAO { get; set; }
[NotMapped]
public String UF_SIGLA { get; set; }
[NotMapped]
public String MUN_DESCRICAO { get; set; }
}
}
DAL :
namespace DAL.utilities
{
public class OperationCadEnderecoEscola
{
public IQueryable<EnderecoEscola> GetId(int idEsc)
{
using (SecurityCtx ctx = new SecurityCtx())
{
ctx.Configuration.LazyLoadingEnabled = false;
var query = ctx.EnderecoEscola.Include("TipoEndereco").Include("UnidadeFederativa").Include("Municipio").Where(w => w.ESCOLA_ID == idEsc).OrderBy(p => p.ENDESC_ENDERECO).ToList().
Select(w => new EnderecoEscola
{
ENDESC_ID = w.ENDESC_ID,
ESCOLA_ID = w.ESCOLA_ID,
TPOEND_ID = w.TPOEND_ID,
ENDESC_UF_ID = w.ENDESC_UF_ID,
ENDESC_MUN_iD = w.ENDESC_MUN_iD,
ENDESC_CEP = w.ENDESC_CEP,
ENDESC_ENDERECO = w.ENDESC_ENDERECO,
ENDESC_NRO = w.ENDESC_NRO,
ENDESC_COMPL = w.ENDESC_COMPL,
ENDESC_BAIRRO = w.ENDESC_BAIRRO,
TPEND_DESCRICAO = w.TipoEndereco.TPEND_DESCRICAO != null ? w.TipoEndereco.TPEND_DESCRICAO : w.TPEND_DESCRICAO,
UF_SIGLA = w.UnidadeFederativa.UF_SIGLA != null ? w.UnidadeFederativa.UF_SIGLA : w.UF_SIGLA,
MUN_DESCRICAO = w.Municipio.MUN_DESCRICAO != null ? w.Municipio.MUN_DESCRICAO : w.MUN_DESCRICAO
}).Distinct().AsQueryable();
return query;
}
}
}
}
When applying for inclusion in ASPxGridView a new record and the method in DAL public IQueryable <EnderecoEscola> getId (int idEsc) is invoked to retrieve the data and they do not exists it is adding a new record on the master and detail occurs error
A field or property with name 'TPEND_DESCRICAO' was not found in the
selected data source.
Someone could guide me on how to solve the problem.
Tks.