I am trying to use ExpressMapper to map data entities to models.
If I map entity to a model directly (both of them having same properties) then it is working fine.
But if I map linked entities to model then I am getting an error
There was an error: System.MissingMethodException: No
parameterless constructor defined for this object.
Database structure:
ExpressMapper Registration:
Mapper.Register<DiscountDaysOfWeek, DiscountDaysOfWeekModel>()
.Member(dest => dest.DiscountDayId, src => src.DiscountDayId)
.Member(dest => dest.DiscountDaysOfWeekId, src => src.DiscountDaysOfWeekId)
.Member(dest => dest.DiscountId, src => src.DiscountId)
.Member(dest => dest.Discountday, src => src.DiscountDay.Day);
Invoked like this:
var disDays = discs.SelectMany(x => x.DiscountDaysOfWeeks)
.Map<IQueryable<DiscountDaysOfWeek>, IQueryable<DiscountDaysOfWeekModel>>();
Getting the error message at the invoke.
DiscountDaysOfWeekModel:
public class DiscountDaysOfWeekModel
{
public int DiscountDaysOfWeekId { get; set; }
public int DiscountId { get; set; }
public int DiscountDayId { get; set; }
public string Discountday { get; set; }
}
DiscountDayOfWeek (Generated by EF)
public partial class DiscountDaysOfWeek
{
public int DiscountDaysOfWeekId { get; set; }
public int DiscountId { get; set; }
public int DiscountDayId { get; set; }
public virtual DiscountDay DiscountDay { get; set; }
public virtual Discount Discount { get; set; }
}
DiscountDay(Generated by EF):
public partial class DiscountDay
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public DiscountDay()
{
this.DiscountDaysOfWeeks = new HashSet<DiscountDaysOfWeek>();
}
public int DiscountDayId { get; set; }
public string Day { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<DiscountDaysOfWeek> DiscountDaysOfWeeks { get; set; }
}
Sample working one: In the below working sample the model and entities are having same properties
Mapper.Register<DiscountPreventedPriceEnding, DiscountPreventedPriceEndingModel>();
var execPriceEndings = discs.SelectMany(x => x.DiscountPreventedPriceEndings)
.Map<IQueryable<DiscountPreventedPriceEnding>, IQueryable<DiscountPreventedPriceEndingModel>>();
Any help would be greatly appreciated.
I appreciate this is an extremely old question, but given that I just spent 4 hours debugging a similar There was an error: System.MissingMethodException: No parameterless constructor defined for this object error on ExpressMapper, I thought I'd chime in with my findings.
So we had a situation similar to yours, in that we had domain models like so (all the following is simplified examples):
public class Owner
{
public int? ID { get; set; }
public string Name { get; set; }
}
public class Animal
{
public int? ID { get; set; }
public string Name { get; set; }
public int? OwnerID { get; set; }
[ForeignKey("OwnerID")]
public Owner Owner { get; set; }
}
With the following view model (i.e. what our APIs send out and receive):
public class AnimalViewModel
{
public int? ID { get; set; }
public string Name { get; set; }
public string Owner { get; set; }
}
With mappings like so:
Mapper.Register<Animal, AnimalViewModel>();
Mapper.Register<AnimalViewModel, Animal>();
On mapping to or from the domain model and the view model we'd get the MissingMethodException, despite the fact that both the view model and the domain model had public, default constructors. The solution was to manually map the related entities in the domain model and exclude them from ExpressMapper's mappings like so:
Mapper.Register<Animal, AnimalViewModel>()
.Ignore(a => a.Owner);
Mapper.Register<AnimalViewModel, Animal>()
.Ignore(a => a.Owner);
From reading EntityMapper's source code, it seems the MissingMethodException is a total red herring which has nothing to do with the actual issue. The actual issue seems to be that it can't figure out how to convert one type to another. In our case -- where complex objects were mapped to/from primitives as above -- it was sufficient to exclude the related objects from the mapper and do it manually.
EDIT:
Upon further investigation, we traced the root problem in our case back to the fact that EF proxy creation creates generated types (e.g. 'MyModel_14289012') which don't match the types registered in the mapper. To prevent this, apply the following to your context:
Context.Configuration.LazyLoadingEnabled = false;
Context.Configuration.ProxyCreationEnabled = false;
and manually include any nested/related objects required in your model like so:
Context.Animals
.Include(a => a.Owner);
This fetches the related entities, but as their actual type rather than the EF-generated type.
Entity Framework uses a parameterless constructor to instantiate classes and reflection to populate class properties. If you have constructors with parameters, then the default parameterless constructor is hidden and you have to add it to your Entity classes for Entity Framework to use.
But if I map linked entities to model then I am getting an error
If your child entities are missing the parameterless constructor and lazy loaded, then EF is failing when it attempts to instantiate the child entity which doesn't have a parameterless constructor.
Note: the parameterless constructor doesn't have to be public.
Related
Source models:
public class ExampleModel
{
public int Id { get; set; }
public float Something { get; set; }
public string Info { get; set; } = "";
}
public class ExampleModelContainer
{
public int Id { get; set; }
public ExampleModel Model { get; set; } = null!;
}
public class LargeEntity
{
public int Id { get; set; }
public List<ExampleModelContainer> ModelEntries { get; set; } = null!;
}
Target models:
public class ExampleModelDto
{
public float Something { get; set; }
public string Info { get; set; } = "";
}
public class LargeEntityDto
{
public int Id { get; set; }
public List<ExampleModelDto> Models { get; set; } = null!;
}
AutoMapper profile:
public class AutoMapperProfile : Profile
{
public AutoMapperProfile()
{
CreateMap<ExampleModel, ExampleModelDto>();
// One of my attempt, I thought converting container into model, and automatically example model into DTO. Failed
CreateMap<ExampleModelContainer, ExampleModel>()
.ConvertUsing(x => x.Model);
CreateMap<LargeEntity, LargeEntityDto>()
.ForMember(x => x.Models,
opt => opt.MapFrom(y => y.ModelEntries));
}
}
Expected result:
LargeEntities' List<ExampleModelContainer> collection is mapped into List<ExampleModelDto>.
Actual result:
Unhandled exception. AutoMapper.AutoMapperConfigurationException: The following member on AutoMapperExps.Models.LargeEntityDto cannot be mapped:
Models
Add a custom mapping expression, ignore, add a custom resolver, or modify the destination type AutoMapperExps.Models.LargeEntityDto.
Context:
Mapping to member Models from AutoMapperExps.Models.LargeEntity to AutoMapperExps.Models.LargeEntityDto
Exception of type 'AutoMapper.AutoMapperConfigurationException' was thrown.
at AutoMapper.Configuration.ConfigurationValidator.AssertConfigurationIsValid(IEnumerable`1 typeMaps)
at AutoMapper.Configuration.ConfigurationValidator.AssertConfigurationExpressionIsValid(IEnumerable`1 typeMaps)
at AutoMapper.MapperConfiguration.AssertConfigurationIsValid()
at Program.Main(String[] args) in D:\Experiments\AutoMapperExps\Program.cs:line 1
How I see it possible to be made:
Mapper takes source List<ExampleModelContainer> collection
Mapper Selects Model property from each element of collection
Mapper projects ExampleModel (returned from property above) into ExampleModelDto
Mapper returns List<ExampleModelDto> as a final result.
Note: This is made for Entity Framework queries. I want to do most projection operations on server-side.
TLDR: AutoMapper throws the exception because it cannot find a mapping ExampleModelContainer -> ExampleDto. If you define a mapping the error is fixed, e.g.:
CreateMap<ExampleModelContainer, ExampleModelDto>()
.IncludeMembers(x => x.Model);
The mapping tries to take several steps at once. If I understand your sample right, the configured mappings are like this:
ExampleModel -> ExampleDto
ExampleModelContainer -> ExampleModel
LargeEntity -> LargeEntityDto
When mapping the Models property in for LargeEntityDto, you are trying to map a List<ExampleModelContainer> without further configuration to a List<ExampleModelDto>. It may seem clear for AutoMapper to take the route
ExampleModelContainer -> ExampleModel -> ExampleDto
in this case, because there is only one path. But what if there were several paths to get from a ExampleModelContainer to a ExampleDto? The library would not be able to make a decision that solves all possible combinations.
This means that you as a developer have to make the decision by configuring a mapping from ExampleModelContainer to ExampleModelDto, e.g.:
CreateMap<ExampleModelContainer, ExampleModelDto>()
.IncludeMembers(x => x.Model);
This way, AutoMapper has a direct mapping between the types and is able to map the properties. See this fiddle to test.
I'm working with the Entity Framework to provide access to a datastore - however, I'm running into an error that I don't quite understand.
Specifically, 'The entity type AnomalyQuery is not part of the model for the current context.'
This error occurs at
using (PHSRP_DashboardDBEntities _DBC = new PHSRP_DashboardDBEntities())
{
//to be replaced by proper table -- anomaly query
var ListAnomalies = _DBC.AnomalyQueries
.OrderBy(p => p.QueryName)
.ToList();
lbx_PickAnomalies.DataSource = ListAnomalies;
}
PHSRP_DashboardDBEntities (which extends DbContext), has the following code:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<AnomalyQuery>().ToTable("AnomalyQuery");
modelBuilder.Entity<AnomalyParameter>().ToTable("AnomalyParameter");
throw new UnintentionalCodeFirstException();
}
I implemented this due to an answer I found here, however I'm not sure it's relevant as it's never referenced.
Additionally, the following DbSets are instantiated within PHSRP_DashboardDBEntities:
public virtual DbSet<AnomalyParameter> AnomalyParameters { get; set; }
public virtual DbSet<AnomalyQuery> AnomalyQueries { get; set; }
These two classes (AnomalyParameter and AnomalyQuery) are defined within the DataModel for PHSRP_DashboardDBEntities, thus should be valid classes.
E.g.
public partial class AnomalyQuery
{
public AnomalyQuery()
{
this.AnomalyParameters = new ObservableListSource<AnomalyParameter>();
}
public int QueryID { get; set; }
public string QueryName { get; set; }
public string QueryText { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ObservableListSource<AnomalyParameter> AnomalyParameters { get; set; }
}
Is defined within PHSRP_DashboardDataModel.tt
Thus, to me, it seems that the entity type AnomalyQuery is certainly part of the model for the current context, and, as a result, I'm not sure how to resolve this error.
I am using Lazy Loading for EF Core 2.2.3 with proxies which works well with DbSets. Now I have to load data from a SQL View and am using DbQuery for this. When trying to load related data for the entity used in the query, I'm getting a DetachedLazyLoadingWarning:
Error generated for warning
'Microsoft.EntityFrameworkCore.Infrastructure.DetachedLazyLoadingWarning:
An attempt was made to lazy-load navigation property 'ProjectStatus'
on detached entity of type 'ProjectProxy'. Lazy-loading is not
supported for detached entities or entities that are loaded with
'AsNoTracking()'.'. This exception can be suppressed or logged by
passing event ID 'CoreEventId.DetachedLazyLoadingWarning' to the
'ConfigureWarnings' method in 'DbContext.OnConfiguring' or
'AddDbContext'.
I don't use AsNoTracking() anywhere in my code.
The DbQuery is defined in OnModelCreating of the context. Excerpt:
modelBuilder.Query<ProjectView>()
.ToQuery(() => Projects
.Select(p => new ProjectView()
{
Id = p.Id,
ProjectCategory = p.ProjectCategory,
ProjectPhase = p.ProjectStatus.ProjectPhase,
}));
Projects is a DbSet of the context.
Project.ProjectCategory is a notMapped-Readonly-Property that uses the relation Project.ProjectStatus.
The Properties of the context:
public virtual DbSet<Project> Projects { get; set; }
public virtual DbSet<ProjectStatus> ProjectStatus { get; set; }
public virtual DbQuery<ProjectView> ProjectViews { get; set; }
Excerpt of the classes:
public partial class Project
{
[NotMapped]
public string ProjectCategory
{
get
{
if (this.ProjectStatus == null)
return string.Empty;
var foo = "someweiredcalculations";
return foo
}
}
public virtual ProjectStatus ProjectStatus { get; set; }
public int ProjectStatusId { get; set; }
public int Id { get; set; }
}
public class ProjectView
{
public int Id { get; set; }
public string ProjectCategory { get; set; }
public string ProjectPhase { get; set; }
}
public partial class ProjectStatus : BaseEntity, IIdEntity<int>
{
public int Id { get; set; }
public string ProjectPhase { get; set; }
public virtual ICollection<Project> Projects { get; set; } = new HashSet<Project>();
}
How can I make Lazy Loading work for this DbQuery?
Thank you very much.
This is just a bug of sorts (haven't found work around and issue is still open). Also read this. As advised and I’m quoting
Note that the warning can be configured to not throw using ConfigureWarnings in the DbContextOptionsBuilder.
This seems to be by design, regardless whether .AsNoTracking() is used or not. I did not find any documentation on this.
If you are stuck on .net core 2 the only workaround I found was to load related entities in a separate query. Effectively breaking lazy loading.
As of .net core 3+ it is possible to work around this by eager loading related properties (.Include(x => x.ProjectStatus)) when Lazy Loading is Used. This was fixed by: https://github.com/aspnet/EntityFrameworkCore/issues/12780. And the error message when using lazy loading was changed to: 'Unable to track an instance of type 'FooQuery' because it does not have a primary key. Only entity types with primary keys may be tracked.'
I'm trying to figure out, how to implement navigation properties to my entities... But my navigation properties is always null:
I've set up two entities:
Entity 1 contains this lines:
public int Id { get; set; }
public ICollection<BestellterArtikel> BestellteArtikel { get; set; }
My second entity looks like this:
public int Id { get; set; }
public int BestellungId { get; set; }
public Bestellung BestellteArtikel { get; set; }
Further more I included this line to my overwritten OnModelCreating-Method:
modelBuilder.Entity<Bestellung>().HasMany(e => e.BestellteArtikel).WithRequired(e => e.Bestellung);
What have I done wrong? Have I forgotten something important? And does it has to be so complex? Do I have to add a line in my overwritten method for each property?
Here is my solution :
Entity 1:
public virtual ICollection<BestellterArtikel> BestellteArtikel { get; set; }
Entity 2:
public virtual Bestellung BestellteArtikel { get; set; }
Edited:
also you have to revise your mapping:
modelBuilder.Entity<Bestellung>().HasMany(e => e.BestellteArtikel).WithRequired(e => e.BestellteArtikel );
Instead of referring to BestellteArtikel property, you referred to type!
What do you mean by "always null"?
If you are talking about null values when you try to read them from DB,
then remember that you need to eagerly load the navigation properties when you query the context,
or use EF lazy-loading.
Read this for more information.
I'm trying to new ICollections in my derived classes - should this be done in the object constructor or/and when I'm creating a new instance of an object in my Register ActionResult()?
Tenant inherits from UserProfile - simplified example:
public class Tenant : UserProfile
{
public Tenant()
{
this.ReferencePhotos = new List<ReferencePhoto>();
// ReferencePhoto extends Image
}
// A Tenant can have many ReferencePhotos
[ForeignKey("ImageId")] // Id of parent class
public virtual ICollection<ReferencePhoto> ReferencePhotos { get; set; }
}
I've tried to do the above but it results in an InvalidCastException:
Unable to cast object of type 'System.Collections.Generic.List'1[Namespace.Models.ReferencePhoto]' to type [Namespace.Models.ReferencePhoto]'.
Why is it trying cast from one object to another when they're the same?
In my Register ActionResult() I've also tried this (with and without setting ICollections in object contructor):
public ActionResult Register(RegisterModel model)
{
using (var db = new LetLordContext())
{
var tenant = db.UserProfile.Create<Tenant>();
tenant.ReferencePhotos = new List<ReferencePhoto>();
// Do I need to new it here at all/as well?
db.UserProfile.Add(tenant); // Exception being thrown here
db.SaveChanges();
Roles.AddUserToRole(model.UserName, "Tenant");
WebSecurity.Login(model.UserName, model.Password);
return RedirectToAction("Confirm", "Home", tenant);
}
}
The above also throws the same exception mentioned earlier. Can anyone offer any insight?
EDIT: Added UserProfile code
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.None)]
public int UserId { get; set; }
[Display(Name = "Username")]
[Required(ErrorMessage="Username is required.")]
public string UserName { get; set; }
[Display(Name = "First name")]
[Required(ErrorMessage = "First name is required.")]
public string FirstName { get; set; }
[Required(ErrorMessage = "Account type is required.")]
public AccountType AccountType;
public virtual string AccountTypeString
{
get { return AccountType.ToString(); }
set
{
AccountType newValue;
if (Enum.TryParse(value, out newValue))
{ AccountType = newValue; }
}
}
}
EDIT: Added context code and ReferencePhoto code
public class LetLordContext : DbContext
{
public DbSet<LetLord.Models.UserProfile> UserProfile { get; set; } // 1 DbSet for superclass UserProfile
public DbSet<LetLord.Models.Image> Image { get; set; } // 1 DbSet for superclass Image
public DbSet<LetLord.Models.ResidentialProperty> ResidentialProperty { get; set; }
public DbSet<LetLord.Models.TenantGroupMember> TenantGroupMember { get; set; }
public DbSet<LetLord.Models.Viewing> Viewing { get; set; }
public DbSet<LetLord.Models.TenantPreferences> TenantPreferences { get; set; }
public DbSet<LetLord.Models.LandlordPreferences> LandlordPreferences { get; set; }
public DbSet<LetLord.Models.Address> Address { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
I'm using table-per-type inheritance hence only DbSets for base classes are implemented.
public class ReferencePhoto : Image
{
// 1:many with Tenant
public int UserId { get; set; }
[ForeignKey("UserId")]
public virtual Tenant Tenant { get; set; }
}
I can workaround this issue by not initialising the list in the object constructor or when creating a new entity. To achieve this I use a null coalescing operator in the GET ActionResult that returns a Tenant object in a partial view. In the partial, I check if Model.ReferencePhotos == null. If it is, a user can upload a photo. When a photo is uploaded, it is added to the list, I can confirm this by checking the database. However, when I login again, the if in the partial view mentioned previously throws the following exception:
Unable to set field/property ReferencePhotos on type System.Data.Entity.DynamicProxies.Tenant_...
with an inner exception:
Unable to cast object of type 'System.Data.Entity.DynamicProxies.ReferencePhoto_3DFB9F64061D55E5AF6718A74C97025F77EFB2BB9C2A6E43F5A6AF62A6A73E75' to type 'System.Collections.Generic.ICollection`1[LetLord.Models.ReferencePhoto]'."}
This may provide more insight.
Try removing the...
[ForeignKey("ImageId")] // Id of parent class
ForeignKey that should be set on the 'one' side (of one-to-many - sort
of), never on collections - and it's only defined on the ReferencePhoto (via UserId
which you already have attributed).
...and that might as well be adding extra foreign key - and resulting in that single instance vs collection error.
Some more info on how ForeignKey should be defined (ForeignKey vs InverseProperty etc.), and some good advices from gurus :)
Entity Framework 4.1 InverseProperty Attribute
How Should I Declare Foreign Key Relationships Using Code First Entity Framework (4.1) in MVC3?
For more complex scenarios (with many-to-many and manually defining relations in fluent code - which I recommend) - take a look at these detailed examples I made a while ago - it has most of the mappings you may need.
Many to many (join table) relationship with the same entity with codefirst or fluent API?
Code First Fluent API and Navigation Properties in a Join Table
EF code-first many-to-many with additional data