Patient.cs //This is Patient Model Class
namespace HMS.Models
{
public class Patient
{
[Key]
public string Id { get; set; }
public string Name { get; set; }
public int age { get; set; }
public int Weight { get; set; }
public string Gender { get; set; }
public string Address { get; set; }
public string PhoneNo { get; set; }
public string Disease { get; set; }
[JsonIgnore]
public IList<DoctorPatient> DoctorPatients { get; set; }
public InPatient InPatients { get; set; }
public OutPatient OutPatients { get; set; }
}
}
InPatient.cs //This InPatient Model Class
namespace HMS.Models
{
public class InPatient
{
[ForeignKey("Patient")]
public string InPatientId { get; set; }
public string RoomNo { get; set; }
public DateTime DateOfAddmission { get; set; }
public DateTime DateOfDischarge { get; set; }
public int Advance { get; set; }
public string LabNo { get; set; }
public Patient Patient { get; set; }
}
}
Here Patient and InPatient Attribute have one-to-one relationship
ViewInPatient.cs
namespace HMS.Models
{
public class ViewInPatient
{
public string Name { get; set; }
public int age { get; set; }
public int Weight { get; set; }
public string Gender { get; set; }
public string Address { get; set; }
public string PhoneNo { get; set; }
public string Disease { get; set; }
public string RoomNo { get; set; }
public DateTime DateOfAddmission { get; set; }
public DateTime DateOfDischarge { get; set; }
public int Advance { get; set; }
public string LabNo { get; set; }
}
}
Here is my DbContext class
public class ApplicationDbContext:DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options):base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<DoctorPatient>()
.HasOne(x => x.Doctor)
.WithMany(dp => dp.DoctorPatients)
.HasForeignKey(di => di.DoctorId);
modelBuilder.Entity<DoctorPatient>()
.HasOne(y => y.Patient)
.WithMany(dp => dp.DoctorPatients)
.HasForeignKey(pi => pi.PatientId);
}
public DbSet<Patient> Patients { get; set; }
public DbSet<Doctor> Doctors { get; set; }
public DbSet<DoctorPatient> DoctorPatients { get; set; }
public DbSet<InPatient> InPatients { get; set; }
//public DbQuery<ViewInPatient> ViewInPatients { get; set; }
}
How to get all data of both Patients and InPatients Table like in ViewInPatient class? (I tried to create a view in sql server but in add table window it shows InPatient instead of InPatients and it return null value)
You can join both models in a Linq expression and return ViewInPatient list:
var ViewInPatient_set =
YourContext
.InPatients
.Select(i=> new ViewInPatient()
{
Name = i.Patient.Name,
// ...
RoomNo = i.RoomNo,
// ...
}
)
.ToList(); // <-- transform to list is optional
I have the following classes.
public class Candidate
{
public long Id { get; set; )
public List<JobAssigned> JobAssigned { get; set; }
}
public class JobAssigned
{
public long Id { get; set; }
public List<StageScore> StageScore { get; set; }
public List<CriteriaScore> CriteriaScore { get; set; }
public List<StageComment> StageComment { get; set; }
}
public class StageComment
{
public long Id { get; set; }
public JobAssigned JobAssigned { get; set; }
public long JobAssignedId { get; set; }
public long PipelineStageId { get; set; }
public long CandidateId { get; set; }
public long JobId { get; set; }
public string Comment { get; set; }
}
public class StageScore
{
public long Id { get; set; }
public JobAssigned JobAssigned { get; set; }
public long JobAssignedId { get; set; }
public long Rating { get; set; }
public long PipelineStageId { get; set; }
public long CandidateId { get; set; }
public long JobId { get; set; }
}
public class CriteriaScore
{
public long Id { get; set; }
public JobAssigned JobAssigned { get; set; }
public long JobAssignedId { get; set; }
public long Rating { get; set; }
public long PipelineStageCriteriaId { get; set; }
public long CandidateId { get; set; }
public long JobId { get; set; }
}
I want eager load all the related table at once. I was trying to the followning,
List<Candidate> candidate = _context.Candidates.
Include(f => f.JobAssigned.Select(g => g.StageScore))
.OrderBy(x => x.Id).ToList();
When I did .Select().Select() it was giving an error. How to get all the collections in a single query?
Look at this article I wrote, it loads all the objects dynamically.
And here is how you could include all objects.
I hope that there won't be circle references.
The plugin I wrote in the above url can handle circle references
List<Candidate> candidate = _context.Candidates.
Include(f => f.JobAssigned.Select(g => g.StageScore.Select(a=> a.JobAssigned))).
Include(f => f.JobAssigned.Select(g => g.CriteriaScore.Select(a=> a.JobAssigned))).
Include(f => f.JobAssigned.Select(g => g.StageComment.Select(a=> a.JobAssigned))).
OrderBy(x => x.Id).ToList();
Getting straight to the point, I've got the following Models:
public abstract class ControlData
{
public DateTime CreatedDate { get; set; }
public int CreatedById { get; set; }
[ForeignKey("CreatedById")]
public Collaborator CreatedBy { get; set; }
public DateTime? UpdatedDate { get; set; }
public int? UpdatedById { get; set; }
[ForeignKey("UpdatedById")]
public Collaborator UpdatedBy { get; set; }
}
[Table("My_Position_Table")]
public class Position : ControlData
{
[Key]
[Column("PositionId")]
public int Id { get; set; }
[Column("PositionStatusId")]
public int StatusId { get; set; }
[ForeignKey("StatusId")]
public PositionStatus Status { get; set; }
public int OpportunityId { get; set; }
[ForeignKey("OpportunityId")]
public Opportunity Opportunity { get; set; }
public int Total { get; set; }
[Column("PositionDurationId")]
public int DurationId { get; set; }
[ForeignKey("DurationId")]
public PositionDuration Duration { get; set; }
public DateTime StartDate { get; set; }
//TODO Agregar las otras propiedades con sus respectivos catalogos
public string PracticeId { get; set; }
[ForeignKey("PracticeId")]
public Practice Practice { get; set; }
public int RoleId { get; set; }
[ForeignKey("RoleId")]
public PersonRole Role { get; set; }
public int PlatformId { get; set; }
[ForeignKey("PlatformId")]
public Platform Platform { get; set; }
public int LevelId { get; set; }
[ForeignKey("LevelId")]
public Level Level { get; set; }
public int EnglishLevelId { get; set; }
[ForeignKey("EnglishLevelId")]
public EnglishLevel EnglishLevel { get; set; }
public string CountryId { get; set; }
public int LocationId { get; set; }
[ForeignKey("LocationId")]
public Location Location { get; set; }
public int? OfficeId { get; set; }
public int OperationId { get; set; }
[ForeignKey("OperationId")]
public Person Operation { get; set; }
public int? EvaluatorId { get; set; }
[ForeignKey("EvaluatorId")]
public Collaborator Evaluator { get; set; }
public int? SourcerId { get; set; }
[ForeignKey("SourcerId")]
public Collaborator Sourcer { get; set; }
public List<Candidate> Candidates { get; set; }
public int? PositionCancellationReasonId { get; set; }
[ForeignKey("PositionCancellationReasonId")]
public PositionCancellationReason CancellationReason { get; set; }
public string CancellationComments { get; set; }
public int? CancellationById { get; set; }
[ForeignKey("CancellationById")]
public Collaborator CancellationBy { get; set; }
public DateTime? CancellationDate { get; set; }
public bool Active { get; set; }
public bool WhereAvailable { get; set; }
public bool RequestAsset { get; set; }
public string CityZone { get; set; }
public string TravelsTo { get; set; }
public string Description { get; set; }
public string SpecificationFile { get; set; }
public int PositionPriorityId { get; set; }
public int? SourcingGroupId { get; set; }
}
[Table("My_Opportunity_Table")]
public class Opportunity : ControlData
{
[Column("OpportunityId")]
[Key]
public int Id { get; set; }
[Column("OpportunityStatusId")]
public int StatusId { get; set; }
[ForeignKey("StatusId")]
public OpportunityStatus Status { get; set; }
public string ProjectId { get; set; }
[ForeignKey("ProjectId")]
public Project Project { get; set; }
public string MarketId { get; set; }
[ForeignKey("MarketId")]
public Market Market { get; set; }
public string CustomerId { get; set; }
[ForeignKey("CustomerId")]
public Customer Customer { get; set; }
public string Name { get; set; }
[Column("OpportunityTypeId")]
public int TypeId { get; set; }
[ForeignKey("TypeId")]
public OpportunityType Type { get; set; }
[Column("OpportunityPriorityId")]
public int PriorityId { get; set; }
[ForeignKey("PriorityId")]
public OpportunityPriority Priority { get; set; }
public int? OpportunityCancellationReasonId { get; set; }
[ForeignKey("OpportunityCancellationReasonId")]
public OpportunityCancellationReason CancellationReason { get; set; }
public string CancellationComments { get; set; }
public int? CancellationById { get; set; }
[ForeignKey("CancellationById")]
public Collaborator CancellationBy { get; set; }
public DateTime? CancellationDate { get; set; }
public bool Active { get; set; }
public List<OpportunityRole> OpportunityRoles { get; set; }
public List<Position> Positions { get; set; }
}
And also, I've got their equivalents in DTO's:
public abstract class ControlDataDTO
{
public DateTime CreatedDate { get; set; }
public int CreatedById { get; set; }
public CollaboratorPlainDTO CreatedBy { get; set; }
public DateTime? UpdatedDate { get; set; }
public int? UpdatedById { get; set; }
public CollaboratorPlainDTO UpdatedBy { get; set; }
}
public class PositionDTO: ControlDataDTO
{
public int Id { get; set; }
public int StatusId { get; set; }
public PositionStatusDTO Status { get; set; }
public int OpportunityId { get; set; }
public OpportunityDTO Opportunity { get; set; }
public int Total { get; set; }
public int DurationId { get; set; }
public PositionDurationDTO Duration { get; set; }
public DateTime StartDate { get; set; }
public string PracticeId { get; set; }
public PracticeDTO Practice { get; set; }
public int RoleId { get; set; }
public PersonRoleDTO Role { get; set; }
public int PlatformId { get; set; }
public PlatformDTO Platform { get; set; }
public int LevelId { get; set; }
public LevelDTO Level { get; set; }
public int EnglishLevelId { get; set; }
public EnglishLevelDTO EnglishLevel { get; set; }
public string CountryId { get; set; }
public int LocationId { get; set; }
public LocationDTO Location { get; set; }
public int? OfficeId { get; set; }
public int OperationId { get; set; }
public PersonDTO Operation { get; set; }
public string OperationIS { get; set; }
public bool WhereAvailable { get; set; }
public bool RequestAsset { get; set; }
public string CityZone { get; set; }
public string TravelsTo { get; set; }
public string Description { get; set; }
public int CandidatesAccepted { get; set; }
public int CandidatesRejected { get; set; }
public int CandidatesWaiting { get; set; }
public bool HasCandidatesWaiting { get; set; }
public int TotalCandidates { get; set; }
public string SpecificationFile { get; set; }
public int? EvaluatorId { get; set; }
public int? SourcerId { get; set; }
public CollaboratorDTO Sourcer { get; set; }
public int? SourcingGroupId { get; set; }
public PositionCancellationReasonDTO CancellationReason { get; set; }
}
public class OpportunityDTO: ControlDataDTO
{
public int Id { get; set; }
public int StatusId { get; set; }
public OpportunityStatusDTO Status { get; set; }
public string ProjectId { get; set; }
public ProjectDTO Project { get; set; }
public string MarketId { get; set; }
public MarketDTO Market { get; set; }
public string CustomerId { get; set; }
public CustomerDTO Customer { get; set; }
public string Name { get; set; }
public int TypeId { get; set; }
public OpportunityTypeDTO Type { get; set; }
public int PriorityId { get; set; }
public OpportunityPriorityDTO Priority { get; set; }
public int? OpportunityCancellationReasonId { get; set; }
public OpportunityCancellationReasonDTO CancellationReason { get; set; }
public string CancellationComments { get; set; }
public int? CancellationById { get; set; }
public CollaboratorPlainDTO CancellationBy { get; set; }
public DateTime? CancellationDate { get; set; }
public CollaboratorDTO Responsible { get; set; }
public List<OpportunityRoleDTO> OpportunityRoles { get; set; }
public int TotalPositions { get; set; }
public bool CandidatesWarning { get; set; }
public bool Active { get; set; }
public List<PositionDTO> Positions { get; set; }
}
For this mapping initialization we are using Profiles, like this way:
public class AutoMapperConfig
{
public static void RegisterMappings()
{
Mapper.Initialize(cfg =>
{
// ...
cfg.AddProfile<OpportunityMappingProfile>();
// ...
});
}
}
public class OpportunityMappingProfile : Profile
{
public OpportunityMappingProfile()
{
CreateMap<Opportunity, OpportunityDTO>()
.ForMember(x => x.Responsible, x => x.MapFrom(c => GetFromOpportunityRoles(c.OpportunityRoles, Constants.OpportunityResponsible)))
.ForMember(x => x.TotalPositions, x => x.MapFrom(c => c.Positions.Count()))
.ForMember(x => x.CandidatesWarning, x => x.MapFrom(c => c.Positions.Count() > 0 ?
c.Positions.Any(pos => pos.Candidates.Any(cand => cand.StatusId == 3)) :
false))
.ForMember(x => x.CreatedBy, x => x.MapFrom(c => Mapper.Map<CollaboratorPlainDTO>(c.CreatedBy)))
.ForMember(x => x.UpdatedBy, x => x.MapFrom(c => Mapper.Map<CollaboratorPlainDTO>(c.UpdatedBy)))
.ForMember(x => x.Positions, x => x.MapFrom(c => Mapper.Map<List<PositionDTO>>(c.Positions))).PreserveReferences(); --> Even using this method, StackOverflow exception is still occurring...
CreateMap<OpportunityDTO, Opportunity>()
.ForMember(x => x.CancellationReason, x => x.Ignore())
.ForMember(x => x.CreatedBy, x => x.Ignore())
.ForMember(x => x.UpdatedBy, x => x.Ignore())
.ForMember(x => x.Positions, x => x.Ignore());
}
private Collaborator GetFromOpportunityRoles(List<OpportunityRole> opportunityRoles, string rol)
{
var opportunityRole = opportunityRoles.FirstOrDefault(opp => opp.ProjectRoleTypeId == rol);
return opportunityRoles != null ? opportunityRole.Collaborator : null;
}
}
And finally, the logic that does the mapping where I'm getting the commented error...
public class OpportunityLogic : IOpportunityLogic
{
// Properties...
public OpportunityLogic(parameters list here, though irrelevant for this example)
{
// ...
}
public ActionResponse<List<OpportunityDTO>> GetOpportunitiesWithPositions(int personId)
{
// Information is retrieved from DB, here...
List<Opportunity> listOpportunities = opportunityRepository.Get(
opp => opp.Status,
opp => opp.Market,
opp => opp.Customer,
opp => opp.Type,
opp => opp.Project,
opp => opp.Status,
opp => opp.Positions,
opp => opp.Positions.Select(pos => pos.Candidates),
opp => opp.Positions.Select(pos => pos.Status),
opp => opp.Positions.Select(pos => pos.Practice),
opp => opp.Positions.Select(pos => pos.Role),
opp => opp.Positions.Select(pos => pos.Platform),
opp => opp.Positions.Select(pos => pos.Sourcer));
// After having retrieved data, here I re-define my model.
listOpportunities = listOpportunities
.Where( opp => opp.StatusId == (int)Constants.OpportunityStatus.Open &&
opp.Active == true &&
opp.Positions.Any(pos => pos.StatusId == (int)Constants.PositionStatus.Open &&
pos.Candidates.Any(can => can.PersonId == personId &&
can.Active == true &&
(can.StatusId == (int)Constants.CandidateStatus.Lead ||
can.StatusId == (int)Constants.CandidateStatus.Waiting))))
.ToList();
// MY PROBLEM IS HERE....
var mappedOpportunities = Mapper.Map<List<OpportunityDTO>>(listOpportunities);
return new ActionResponse<List<OpportunityDTO>> (mappedOpportunities);
}
}
My problem starts when trying to map my Model (List) to the DTO (List); the error is the well-known "StackOverflow Exception". If I'm using the "PreserveReferences()" method, why is still throwing the same exception?. The same goes for "MaxDepth() method", after having tried different depth levels (1,2,3...).
I've spent too many hours trying to solve this issue and to be honest, I'm out of ideas already. If anyone has an idea what to do here, I'll be really grateful.
Thanks and advance & regards!!
Starting from 6.1.0 PreserveReferences is set automatically at config time whenever the recursion can be detected statically. If that doesn't happen in your case, open an issue with a full repro and we'll look into it.
http://automapperdocs.readthedocs.io/en/latest/5.0-Upgrade-Guide.html#circular-references
But you have to remove the Map calls inside the MapFroms. Those ForMember-s are not needed.
The issue here is that I was missing another Mapping Profile that needed to preserve its references, but had not mentioned here, since I was missing that part and that was the one that had causing me all the issues.
I am using EF6.1.3. I have 3 poco's pickbatch, order, orderline.
public class PickBatch
{
public int Id { get; set; }
public string Barcode { get; set; }
public byte Status { get; set; }
public string Picker { get; set; }
public DateTime DateCreated { get; set; }
public DateTime? DateModified { get; set; }
public List<Order> Orders { get; set; }
}
public class Boxes
{
public Order()
{
OrderLines = new List<OrderLines>();
}
public int Id { get; set; }
public int? PickBatchId { get; set; }
public string OrderType { get; set; }
public string OrderNumber { get; set; }
public string CustomerNumber { get; set; }
public byte Status { get; set; }
public DateTime DateCreated { get; set; }
public DateTime? DateModified { get; set; }
public List<OrderLine> OrderLines { get; set; }
}
public class OrderLines
{
public int Id { get; set; }
public string Article { get; set; }
public string ArticleDescription { get; set; }
public int QtyOrdered { get; set; }
public int QtyDelivered { get; set; }
public int OrderId { get; set; }
public byte Status { get; set; }
public string Picker { get; set; }
public string PickLocation { get; set; }
public string Sorting { get; set; }
public DateTime DateCreated { get; set; }
public DateTime? DateModified { get; set; }
}
Not all the properties match the column names in the tables. So on model creating i am fixing this.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<PickBatch>().ToTable("PickBatch");
modelBuilder.Entity<PickBatch>().HasKey(b => b.Id);
modelBuilder.Entity<PickBatch>().Property(b => b.Id).HasColumnName("PickBatchId");
modelBuilder.Entity<Order>().HasKey(b => b.Id);
modelBuilder.Entity<Order>().Property(b => b.Id).HasColumnName("OrderId");
modelBuilder.Entity<OrderLine>().HasKey(b => b.Id);
modelBuilder.Entity<OrderLine>().Property(o => .Id).HasColumnName("OrderLineId");
}
When retrieve the orderlines I get an execption: Invalid column name 'PickBatch_Id'. I don't understand why does EF want to add this property?
I have many to many relationship tables such as "User & Notification & UserNotification" and their entities, view models also.
There is only a difference between ViewModel and Entity classes. HasRead property is inside NotificationViewModel. How Can I map this entities to view models? I could not achieve this for HasRead property.
What I did so far is,
Mapping Configuration:
CreateMap<Notification, NotificationViewModel>();
CreateMap<User, UserViewModel>().ForMember(dest => dest.Notifications, map => map.MapFrom(src => src.UserNotification.Select(x => x.Notification)));
Notification class:
public class Notification : IEntityBase
{
public Notification()
{
this.UserNotification = new HashSet<UserNotification>();
}
public int Id { get; set; }
public string Header { get; set; }
public string Content { get; set; }
public System.DateTime CreateTime { get; set; }
public bool Status { get; set; }
public virtual ICollection<UserNotification> UserNotification { get; set; }
}
User Class
public class User : IEntityBase
{
public User()
{
this.UserNotification = new HashSet<UserNotification>();
}
public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public string Email { get; set; }
public string PhoneNumber { get; set; }
public bool Status { get; set; }
public virtual ICollection<UserNotification> UserNotification { get; set; }
}
UserNotification class:
public class UserNotification : IEntityBase
{
public int Id { get; set; }
public int UserId { get; set; }
public int NotificationId { get; set; }
public bool HasRead { get; set; }
public virtual Notification Notification { get; set; }
public virtual User User { get; set; }
}
UserViewModel class
public class UserViewModel : IValidatableObject
{
public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public string Email { get; set; }
public string PhoneNumber { get; set; }
public bool Status { get; set; }
public IList<NotificationViewModel> Notifications { get; set; }
}
NotificationViewModel class
public class NotificationViewModel
{
public int Id { get; set; }
public string Header { get; set; }
public string Content { get; set; }
public System.DateTime CreateTime { get; set; }
public bool Status { get; set; }
public bool HasRead { get; set; } // this is the difference
}
In order to fix up the HasRead, maybe you can utilize the AfterMap(Action<TSource, TDestination> afterFunction) function. It's not as elegant as the rest of automapper, but it might work.
CreateMap<User, UserViewModel>()
.ForMember(dest => dest.Notifications, map => map.MapFrom(src => src.UserNotification.Select(x => x.Notification)))
.AfterMap((src, dest) =>
{
foreach (var notificationVM in dest.Notifications)
{
notificationVM.HasRead = src.UserNotification.Where(x => x.NotificationId == notificationVM.Id).Select(x => x.HasRead).FirstOrDefault();
}
});