With the 6.0.2.0 version, I'm getting StackOverFlow exception everytime I attempt to retrieve a mapping from Model to DTO.
I've tried with PreserveChanges() & MAxDepth(int) methods already but still, nothing achieved.
In the official documentation, there is no sample that explains how to handle Child entities to be mapped. Only what is mentioned below:
// Self-referential mapping
cfg.CreateMap<Category, CategoryDto>().MaxDepth(3);
// Circular references between users and groups
cfg.CreateMap<User, UserDto>().PreserveReferences();
Also in #1639, @lbargaoanu mentioned that we can use ForAllMaps to be set everywhere. But the problem, is that we are using profiles for this and well, I'm not to experienced enough in order to dig the whole idea about what is the solution being commented, my apologizes..
I know I should be missing something for sure, but my question here is "what?"..
Thanks in advance & Best Regards!!
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("MyOpportunityTable")]
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; }
}
[Table("MyPositionTable")]
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; }
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 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; }
}
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; }
}
````
### Target class where I need to catch the expected DTO --> List<OpportunityDTO>
```csharp
public class OpportunityLogic
{
public ActionResponse<List<OpportunityDTO>> GetOpportunitiesWithPositions(int personId)
{
var listOpportunities2 = new List<Opportunity>
{
new Opportunity
{
Id = 2,
Name = "Another Opportunity",
Active = true,
CreatedDate = new DateTime(2017, 7, 10),
Positions = new List<Position> {
new Position
{
Id= 1,
LocationId = 4
},
new Position
{
Id= 2,
LocationId = 4
},
new Position
{
Id= 3,
LocationId = 4
}
}
}
};
var mappedOpportunities = Mapper.Map<List<OpportunityDTO>>(listOpportunities);
return new ActionResponse<List<OpportunityDTO>> (mappedOpportunities);
}
}
````
### Mapping configuration
```csharp
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(); // For some reason, this method is not helping actually... the same for MaxDepth(int)
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;
}
}
6.0.2.0
A ProjectDTO List;
a StackOverflow Exception
1. AutoMapperConfig.RegisterMappings();
2- var myOppLogic = new OpportunityLogic();
3. var myEpectedDTO = myOppLogic.GetOpportunitiesWithPositions(1234);
End..
My first option is to not have any kind of circular reference in the first place. If this is pulling from for example EF or a database, you've got some lazy loading and really bad performance.
Do you actually intend to have circular references between these two? How big of a graph is supposed to be built?
What I usually do instead is to explicitly model levels - Root, Child, Grandchild etc. for the number of levels I expect. MaxDepth can work but it's not obvious. Explicit modeling of your DTO (which can break serializers too) is best.
@jbogard I am in the same situation as the OP and since the requirement set upon me is an API with OData which can expand on every navigation property and back I cannot wipe this under the rug. On top of this I have certain entities referencing themselves, Item -> ParentItem, which can technically go on forever.
I have looked into creating a mapper of my own but stumble upon the same problem as you have: circular reference. How do you suppose Entity Framework solves this problem?
@bdebaere A repro would help. Make a gist that we can execute and see fail.
@lbargaoanu I created an example at https://github.com/bdebaere/AutoMapperSample. When running it and visiting http://localhost:53971/odata/Items it returns the error below.
Execute the ExecuteMe.sql on a database named "EntityFrameworkTesting".
{
"error": {
"code": "",
"message": "An error has occurred.",
"innererror": {
"message": "The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; odata.metadata=minimal'.",
"type": "System.InvalidOperationException",
"stacktrace": "",
"internalexception": {
"message": "The type 'AutoMapperSample.Controllers.DtoItem' 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.",
"type": "System.NotSupportedException",
"stacktrace": " at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.ValidateInitializerMetadata(InitializerMetadata metadata)\r\n at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MemberInitTranslator.TypedTranslate(ExpressionConverter parent, MemberInitExpression linq)\r\n at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TypedTranslator`1.Translate(ExpressionConverter parent, Expression linq)\r\n at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq)\r\n at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TranslateLambda(LambdaExpression lambda, DbExpression input)\r\n at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TranslateLambda(LambdaExpression lambda, DbExpression input, DbExpressionBinding& binding)\r\n at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.OneLambdaTranslator.Translate(ExpressionConverter parent, MethodCallExpression call, DbExpression& source, DbExpressionBinding& sourceBinding, DbExpression& lambda)\r\n at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.SelectTranslator.Translate(ExpressionConverter parent, MethodCallExpression call)\r\n at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.SequenceMethodTranslator.Translate(ExpressionConverter parent, MethodCallExpression call, SequenceMethod sequenceMethod)\r\n at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.TypedTranslate(ExpressionConverter parent, MethodCallExpression linq)\r\n at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TypedTranslator`1.Translate(ExpressionConverter parent, Expression linq)\r\n at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq)\r\n at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.Convert()\r\n at System.Data.Entity.Core.Objects.ELinq.ELinqQueryState.GetExecutionPlan(Nullable`1 forMergeOption)\r\n at System.Data.Entity.Core.Objects.ObjectQuery`1.<>c__DisplayClass7.<GetResults>b__6()\r\n at System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction[T](Func`1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess)\r\n at System.Data.Entity.Core.Objects.ObjectQuery`1.<>c__DisplayClass7.<GetResults>b__5()\r\n at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func`1 operation)\r\n at System.Data.Entity.Core.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption)\r\n at System.Data.Entity.Core.Objects.ObjectQuery`1.<System.Collections.Generic.IEnumerable<T>.GetEnumerator>b__0()\r\n at System.Data.Entity.Internal.LazyEnumerator`1.MoveNext()\r\n at System.Web.OData.Formatter.Serialization.ODataResourceSetSerializer.WriteResourceSet(IEnumerable enumerable, IEdmTypeReference resourceSetType, ODataWriter writer, ODataSerializerContext writeContext)\r\n at System.Web.OData.Formatter.Serialization.ODataResourceSetSerializer.WriteObjectInline(Object graph, IEdmTypeReference expectedType, ODataWriter writer, ODataSerializerContext writeContext)\r\n at System.Web.OData.Formatter.Serialization.ODataResourceSetSerializer.WriteObject(Object graph, Type type, ODataMessageWriter messageWriter, ODataSerializerContext writeContext)\r\n at System.Web.OData.Formatter.ODataMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, HttpContent content, HttpContentHeaders contentHeaders)\r\n at System.Web.OData.Formatter.ODataMediaTypeFormatter.WriteToStreamAsync(Type type, Object value, Stream writeStream, HttpContent content, TransportContext transportContext, CancellationToken cancellationToken)\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.WebHost.HttpControllerHandler.<WriteBufferedResponseContentAsync>d__22.MoveNext()"
}
}
}
}
I see you're using ProjectTo, then you need MaxDepth. But that's not always possible, at least with EF6. Try to write the EF LINQ query without AM. If that works, it should work with AM too.
Entity Framework solves this....poorly. As you might expect, circular/self-referencing tables are weird. You can handle them, but in direct SQL using CTEs.
EF just does lazy loading which can result in horrible performance. If you search "JSON.NET circular reference" you'll see a similar problem. JSON.NET will actually throw an exception unless you tell it to ignore circular references.
That's why I suggest removing any circular reference in your DTOs. It just makes things so so much more complicated.
@lbargaoanu MaxDepth would be fine in this example. But as I said before there are some entities for which this will not work. With references to the parent of the same entity type which is possible ad infinitum. Unless I am not understanding you correctly.
@jbogard I realize that removing circular references would solve everything. But this is a requirement set not by me but by the higher ups. Can you perhaps point me in the right direction to create this myself if it is not offered by AutoMapper?
Yes, and we are saying that's not possible in LINQ, so it's not possible with AM.
But this has nothing to do with the original question :)
Do the higher ups understand the technical limitation of databases and ORMs?
On Wed, Feb 21, 2018 at 8:26 AM bdebaere notifications@github.com wrote:
@lbargaoanu https://github.com/lbargaoanu MaxDepth would be fine in
this example. But as I said before there are some entities for which this
will not work. With references to the parent of the same entity type which
is possible ad infinitum.@jbogard https://github.com/jbogard I realize that removing circular
references would solve everything. But this is a requirement set not by me
but by the higher ups. Can you perhaps point me in the right direction to
create this myself if it is not offered by AutoMapper?—
You are receiving this because you were mentioned.Reply to this email directly, view it on GitHub
https://github.com/AutoMapper/AutoMapper/issues/2539#issuecomment-367342545,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAGYMnKm8b2r3a92OtCUjxYt3obGxBkoks5tXCd3gaJpZM4SMw8o
.
@lbargaoanu I apologize. It did seem to me like they were related at first.
@jbogard No, and this is also new for me I'm afraid. Would it be possible to map expressions on the database entity and not the DTO? If I can map (Amount) => this.SubGroups.Sum(s => s.Quantity) upon the Item entity instead of the DtoItem entity. I need a .Select(s => s.Item.Amount) and navigation properties to work. But without mapping the expression one of course gets the LINQ error: "The specified type member is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported.".
I'm not sure what else to tell you here - first and foremost, I try to remove AutoMapper from the equation to see if I can do what you're asking manually. If that's not possible, then AutoMapper certainly can't do it automatically.
@bdebaere Have you looked at UseAsDataSource?
It's used to Translate IQueryable of DTO to an IQueryable of Entity and return the results mapped or projected as DTO in the end. So you can do all the OData calls and they will be translated automatically.
Ok I looked into it a bit more, and you should be using UseAsDataSource instead of ProjectTo for more functionality with OData. You can use things like Filtering and Sort, but not Expand and Select.
This doesn't solve the issue however.
The real problem is in exception description below
"The type 'AutoMapperSample.Controllers.DtoItem' 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."
So Automapper is making a query that does new DtoITem in 2 places but in both instances aren't setting the same properties in the same order. This is probably because of the item and parent item. One item is setting the child, but after max depth is done it won't set its child and both are structurally incompatible, and thus exception. It's impossible unless you make an ItemDto, ChildItemDto, GrandChildItemDto, ect Entity Framework just won't work in this case.
Firstly, I wish to thank you all for your time and effort to search this issue...
Just to inform you that I've managed to solve this problem, with the help of my colleagues here 👍 .
The problem was in _PositionMappingProfile and in _OpportunityMappingProfile_..
```csharp
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
public int TotalPositions { get; set; }
public bool CandidatesWarning { get; set; }
public bool Active { get; set; }
// public List
}
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 CollaboratorPlainDTO Sourcer { get; set; } ---->> New Navigator Property
public int? SourcingGroupId { get; set; }
public PositionCancellationReasonDTO CancellationReason { get; set; }
}
````
There was another DTO that was missing to be changed too: PositionDTO, that was the culprit in some way.
```csharp
public class OpportunityMappingProfile : Profile
{
public OpportunityMappingProfile()
{
CreateMap
.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
.ForMember(x => x.UpdatedBy, x => x.MapFrom(c => Mapper.Map
.PreserveReferences(); // Note here that I removed the new member I had appended in PositionDTO in this MappingProfile ;)
CreateMap
.ForMember(x => x.CancellationReason, x => x.Ignore())
.ForMember(x => x.CreatedBy, x => x.Ignore())
.ForMember(x => x.UpdatedBy, 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;
}
}
public class PositionMappingProfile : Profile
{
public PositionMappingProfile()
{
CreateMap
.ForMember(x => x.CandidatesAccepted, x => x.MapFrom(c => c.Candidates.Count(can => can.StatusId == (int)Constants.CandidateStatus.Accepted)))
.ForMember(x => x.CandidatesRejected, x => x.MapFrom(c => c.Candidates.Count(can => can.StatusId == (int)Constants.CandidateStatus.Rejected)))
.ForMember(x => x.CandidatesWaiting, x => x.MapFrom(c => c.Candidates.Count(can => can.StatusId == (int)Constants.CandidateStatus.Waiting)))
.ForMember(x => x.HasCandidatesWaiting, x => x.MapFrom(c => c.Candidates.Any(can => can.StatusId == (int)Constants.CandidateStatus.Waiting)))
.ForMember(x => x.TotalCandidates, x => x.MapFrom(c => c.Candidates.Count()))
.ForMember(x => x.Operation, x => x.MapFrom(c => Mapper.Map
.ForMember(x => x.CreatedBy, x => x.MapFrom(c => Mapper.Map
.ForMember(x => x.UpdatedBy, x => x.MapFrom(c => Mapper.Map
.PreserveReferences(); // Sourcer Nav Property is not required here, hence is being ignored.. Only by appending "PreserveReferences()"..
CreateMap
}
````
Since my the required Entity's Nav Properties' names match against the DTOs' Nav Properties' names
_(Opportunity.Positions == OpportunityDTO.Positions)_ and _(Position.Sourcer == PositionDTO.Sourcer)_, there is no need to map the members in _OpportunityMappingProfile_ and _PositionMappingProfile_ respectively.
Only by including _PreserveReferences()_ in the Mapping Profiles commented above, solved my problem.
FYI, in the real scenario, the data is being pulled from EF, but since I needed to simplify my explaination, I had decided to omit this detail.
Once, again I do thank @jbogard, @bdebaere, @lbargaoanu and @TylerCarlson1 for your support..
Sorry I missed someone :P
Best Regards!! : 👍
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.