I have came across a problem where i need to map self referencing table from EF6 to DTO.
This is the table :
The Entity looks like this :
public partial class Page
{
public Page()
{
this.ChildPages = new HashSet<Page>();
}
public int PageId { get; set; }
public string Name { get; set; }
public string ModelName { get; set; }
public bool IsList { get; set; }
public bool IsActive { get; set; }
public bool IsDeleted { get; set; }
public System.DateTime DateCreated { get; set; }
public System.DateTime DateModified { get; set; }
public int Order { get; set; }
public Nullable<int> ParentPageId { get; set; }
public virtual ICollection<Page> ChildPages { get; set; }
public virtual Page ParentPage { get; set; }
}
The DTO Model looks like this :
public class PageViewModel
{
public int PageId { get; set; }
public string Name { get; set; }
public string ModelName { get; set; }
public bool IsList { get; set; }
public bool IsActive { get; set; }
public bool IsDeleted { get; set; }
public System.DateTime DateCreated { get; set; }
public System.DateTime DateModified { get; set; }
public virtual ICollection<PageViewModel> ChildPages { get; set; }
public virtual PageViewModel ParentPage { get; set; }
}
Automapper config looks like this:
config.CreateMap<Page, PageViewModel>().MaxDepth(8)
However when I run this code :
var pages = DB.Pages.ProjectTo<PageViewModel>().ToList();
I get the following exception:
An exception of type 'System.NotSupportedException' occurred in
EntityFramework.SqlServer.dll but was not handled in user code
Additional information: The type 'PageViewModel' appears in two
structurally incompatible initializations within a single LINQ to
Entities query. A type can be initialized in two places in the same
query, but only if the same properties are set in both places and
those properties are set in the same order.
Does anyone have an idea how to solve this issue?
Related
I am trying to create a simple One-to-many relationship but Ef Core somehow does not recognize it. I am still a beginner in this but I think I did this by the book (defined the relationship fully) so I don't get why EF Core is throwing this error:
Unable to determine the relationship represented by navigation
'Asset.Insurance' of type 'Insurance'. Either manually configure the
relationship, or ignore this property using the '[NotMapped]'
attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.
Those are my two models:
Asset.cs
public class Asset
{
public int AssetId { get; set; }
public string AssetName { get; set; }
[ForeignKey("AssetTypeId")]
public int AssetTypeId { get; set; }
public AssetType AssetType { get; set; }
public ICollection<AssetValue> AssetTypeValues { get; set; }
public string Brand { get; set; }
public string Model { get; set; }
public string SerialNumber { get; set; }
public string ProductNumber { get; set; }
public DateTime PurchaseDate { get; set; }
public decimal PurchasePrice { get; set; }
[ForeignKey("LocationId")]
public int? LocationId { get; set; }
public Location Location { get; set; }
[ForeignKey("InsuranceId")]
public int InsuranceId { get; set; }
public Insurance Insurance { get; set; }
[ForeignKey("OwnerId")]
public string? OwnerId { get; set; }
public AppUser Owner { get; set; }
[ForeignKey("InvoiceId")]
public int? InvoiceId { get; set; }
public Insurance Invoice { get; set; }
public string? ImagePath { get; set; }
public string? Description { get; set; }
public string CreatedBy { get; set; }
public string ModifiedBy { get; set; }
public DateTime DateCreated { get; set; }
public DateTime DateModified { get; set; }
}
Insurance.cs
public class Insurance
{
public int InsuranceId { get; set; }
[ForeignKey("InsuranceTypeId")]
public int InsuranceTypeId { get; set; }
public InsuranceType InsuranceType { get; set; }
public string Insurer { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public string? FilePath { get; set; }
public string? Description { get; set; }
public string CreatedBy { get; set; }
public string ModifiedBy { get; set; }
public DateTime DateCreated { get; set; }
public DateTime DateModified { get; set; }
public ICollection<Asset> Assets { get; set; }
}
Also, if I remove this relationship, just for testing, migration still doesn't work and throwing errors about the other foreign keys in the Asset model. Is it because I have too many foreign keys so I have to define them in OnModelCreating?
Edit: ApplicationDbContext
public class ApplicationDbContext : IdentityDbContext<AppUser>
{
public DbSet<Asset> Assets { get; set; }
public DbSet<AssetType> AssetTypes { get; set; }
public DbSet<AssetProp> AssetProps { get; set; }
public DbSet<AssetValue> AssetValues { get; set; }
public DbSet<Location> Locations { get; set; }
public DbSet<Company> Companies { get; set; }
public DbSet<CompanyContact> CompanyContacts { get; set; }
public DbSet<Invoice> Invoices { get; set; }
public DbSet<InsuranceType> InsuranceTypes { get; set; }
public DbSet<Insurance> Insurances { get; set; }
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
}
If you specify the [ForeignKey] attribute, you need to do one of two things:
Add the attribute to the scalar property, and use the name of the navigation property; or
Add the attribute to the navigation property, and use the name of the scalar property.
So either:
[ForeignKey("Insurance")]
public int InsuranceId { get; set; }
public Insurance Insurance { get; set; }
or:
public int InsuranceId { get; set; }
[ForeignKey("InsuranceId")]
public Insurance Insurance { get; set; }
By putting the attribute on the scalar property and specifying the name of the scalar property, EF can't understand what you're trying to do.
This applies to all of your [ForeignKey("...")] attributes in the code.
NB: Since there is only one navigation property to each given entity type, and the scalar property names match the navigation property names with the Id suffix added, the [ForeignKey] attributes aren't actually required.
EDIT:
You have two navigation properties for the Insurance entity:
public Insurance Insurance { get; set; }
...
public Insurance Invoice { get; set; }
I suspect the second one should be:
public Invoice Invoice { get; set; }
I am using code first approach with Entity Framework 6. Three of my model classes implements inheritance and each of these model has collection which also implement inheritance. I am using TPH inheritance strategy. Everything works fine and I can insert/update with no problem at all. However, I get when I try to read data from the repo. The I get is shown below.
I have include my models, entity configuration and the line that throws this exception:
The include path expression must refer to a navigation property defined on the type. Use dotted paths for reference navigation properties and the select operator for collection navigation properties
Code:
public abstract class OrderSup
{
public OrderSup()
{
DetailOrderSups = new HashSet<DetailOrderSup>();
}
public int Id { get; set; }
public string Description { get; set; }
public decimal AmountPaid { get; set; }
public DateTime DateEntered { get; set; }
public string CusSupCode { get; set; }
public decimal NetAmount { get; set; }
public decimal TaxAmount { get; set; }
public string DespatchSatus { get; set; }
public string Reference { get; set; }
}
public abstract class DetailOrderSup
{
[Key, Column(Order = 0)]
public virtual int OrderId { get; set; }
[Key, Column(Order = 1)]
public virtual int ProductId { get; set; }
public virtual Product OrderedProducts { get; set; }
public InvoiceType InvoiceType { get; set; }
public virtual OrderSup OrderSup { get; set; }
}
public class Order : OrderSup
{
public int SalesOrderNumber { get; set; }
public InvoiceType InvoiceType { get; set; }
}
public class PurchaseOrder : OrderSup
{
public string OrderStatus { get; set; }
//public string AlocationStatus { get; set; }
public int InvoiceNumber { get; set; }
}
public class PurchaseOrderDetails : DetailOrderSup
{
public bool IsOrderPaid { get; set; }
public decimal Outstanding { get; set; }
public decimal AmountPaid { get; set; }
public bool IsDisputed { get; set; }
}
public class OrderDetails: DetailOrderSup
{
public bool IsOrderPaid { get; set; }
public decimal Outstanding { get; set; }
}
public IEnumerable<PurchaseOrder> GetPurchaseOrders()
{
// THIS IS LINE THAT THROWS EXCEPTION
return this.AppContext.Orders.OfType<PurchaseOrder>()
.Include(o => o.DetailOrderSups.OfType<PurchaseOrderDetails>());
}
class OrderSupConfiguration : EntityTypeConfiguration<OrderSup>
{
public OrderSupConfiguration()
{
HasMany(p => p.DetailOrderSups)
.WithRequired(o => o.OrderSup)
.HasForeignKey(o => o.OrderId);
}
}
Please what am I doing wrong?
Thanks in advance for your assistance
I have my C# Model classes generated from SQL using ADO.net Entity Model.
I created 2 additional classes which are not generated by ADO which have 1 to many relationship.
The class definition is below:
LISToxPatient
[Table("LISToxPatient")]
public class LISToxPatient
{
public LISToxPatient()
{
LISResults = new HashSet<LISResult>();
}
[Key]
public long LISToxPatientID { get; set; }
public long? PatientID { get; set; }
public long? NetworkID { get; set; }
[StringLength(20)]
public string FirstName { get; set; }
[StringLength(20)]
public string LastName { get; set; }
[StringLength(50)]
public string Prescriber { get; set; }
[StringLength(20)]
public string ResultSummary { get; set; }
[StringLength(20)]
public string Specimen { get; set; }
public virtual ICollection<LISResult> LISResults { get; set; }
}
LIS Result
[TableName("LISResult")]
public class LISResult
{
[Key]
public long LISResultID { get; set; }
public long LISToxPatientID { get; set; }
[StringLength(40)]
public string Remark { get; set; }
[StringLength(30)]
public string Compound { get; set; }
[StringLength(20)]
public string CreateBy { get; set; }
[StringLength(20)]
public string UpdateBy { get; set; }
public DateTime? CreateDT { get; set; }
public DateTime? UpdateDT { get; set; }
public bool? Deleted { get; set; } = false;
public virtual LISToxPatient LISToxPatient { get; set; }
}
Now when I try to add "LISToxPatient" object which holds a collection of "LISResult" entities, I get an error which says:
"Invalid object name dbo.LISResults".
I can see that see error is due to the EF trying to find pluralized table name which doesn't exist in db but all my other table classes use the pluralized table name convention. I tried to add this line
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
but still get the same error.
How can I fix it?
In my project I need to map objects from the external systems to DTOs. The object I want to map is:
public class PriceLists : List<PriceList> { }
I get the idea of mapping properties within the class but having difficulty finding a solution for this case. My DTO will preferably be "identical" to this source class to make it as simple as possible for the moment:
public class PriceListsDTO : List<PriceListDTO> { }
Is there a simple solution or do I need to refactor my DTO object?
Thanks.
Edit: I have tried creating mapping for a list of Price lists without success regarding this problem.
Mapper.Initialize(cfg => { cfg.CreateMap<PriceList>, <PriceListDTO>(); });
Mapper.Initialize(cfg => { cfg.CreateMap<IList<PriceList>, IList<PriceListDTO>>(); });
Edit2:
public class PriceList
{
public string Agreement { get; set; }
public Currency Currency { get; set; }
public string Description { get; set; }
public Nullable<DateTime> EndDate { get; set; }
public int Id { get; set; }
public Nullable<Guid> ImageKey { get; set; }
public bool IsBid { get; set; }
public bool IsLimitedToStock { get; set; }
public bool IsPrimary { get; set; }
public bool IsPublic { get; set; }
public string Name { get; set; }
public Nullable<DateTime> StartDate { get; set; }
public int Type { get; set; }
}
public class PriceListDTO
{
public string Agreement { get; set; }
public CurrencyViewModel Currency { get; set; }
public string Description { get; set; }
public DateTime? EndDate { get; set; }
public int Id { get; set; }
public Guid? ImageKey { get; set; }
public bool IsBid { get; set; }
public bool IsLimitedToStock { get; set; }
public bool IsPrimary { get; set; }
public bool IsPublic { get; set; }
public string Name { get; set; }
public DateTime? StartDate { get; set; }
public int Type { get; set; }
}
And the Currency class and DTO only contains string properties.
From the code you've given, you never actually told AutoMapper to associate the DTO with the model class. If you call Initialize twice, the second will REMOVE any previous mappings. Try updating your configuration to do the following:
Mapper.Initialize( cfg => {
cfg.CreateMap<PriceList, PriceListDTO>()
.ReverseMap();
// Not sure if this is required if you already have the model/dto map
cfg.CreateMap<IList<PriceList>, IList<PriceListDTO>>();
cfg.AssertConfigurationIsValid();
});
public class PriceList
{
public string Agreement { get; set; }
public Currency Currency { get; set; }
public string Description { get; set; }
public Nullable<DateTime> EndDate { get; set; }
public int Id { get; set; }
public Nullable<Guid> ImageKey { get; set; }
public bool IsBid { get; set; }
public bool IsLimitedToStock { get; set; }
public bool IsPrimary { get; set; }
public bool IsPublic { get; set; }
public string Name { get; set; }
public Nullable<DateTime> StartDate { get; set; }
public int Type { get; set; }
}
public class PriceListDTO
{
public string Agreement { get; set; }
public Currency Currency { get; set; }
public string Description { get; set; }
public DateTime? EndDate { get; set; }
public int Id { get; set; }
public Guid? ImageKey { get; set; }
public bool IsBid { get; set; }
public bool IsLimitedToStock { get; set; }
public bool IsPrimary { get; set; }
public bool IsPublic { get; set; }
public string Name { get; set; }
public DateTime? StartDate { get; set; }
public int Type { get; set; }
}
after that try automapper.mapper.createmap it
will work for you otherwise you need to use formember method to map
properties of currency with currencyviewmodel one by one because
object are different to each other just try with it. hope it will help
for you . Thanks
I´m having a big problem to configure the navigation on my application.
These are the bases (but already with problems)
public class ModeloBase
{
[Key()]
public int Id { get; set; }
public int InseridoPorId { get; set; }
[Column(TypeName = "datetime2")]
public DateTime DataInserido { get; set; }
[Column(TypeName = "datetime2")]
public DateTime DataAtualizado { get; set; }
public bool Ativo { get; set; }
#region Navigation
[Required]
[ForeignKey("InseridoPorId")]
public virtual Colaborador InseridoPor { get; set; }
#endregion
}
public class Colaborador : ModeloBase
{
public Colaborador()
{
ColaboradoresSubordinadosPorMim = new HashSet<Colaborador>();
}
public int SuperiorId { get; set; }
[ForeignKey("SuperiorId")]
public Colaborador Superior { get; set; }
public ICollection<Colaborador> ColaboradoresSubordinadosPorMim { get; set; }
}
public class Contato : ModeloBase
{
[Required]
[StringLength(10)]
public string Endereco { get; set; }
}
Basically I have a base class "ModeloBase" that all extends it and I want that all thables have a FK to Colaborador with the Column Name "InseridoPorId"
As soon as I try to generate the controller it keep warning me with Multiplicity problems for these Navigation.
Any help?
Thanks.