{"action":"closed","issue":{"url":"https://api.github.com/repos/aspnetboilerplate/aspnetboilerplate/issues/3470","repository_url":"https://api.github.com/repos/aspnetboilerplate/aspnetboilerplate","labels_url":"https://api.github.com/repos/aspnetboilerplate/aspnetboilerplate/issues/3470/labels{/name}","comments_url":"https://api.github.com/repos/aspnetboilerplate/aspnetboilerplate/issues/3470/comments","events_url":"https://api.github.com/repos/aspnetboilerplate/aspnetboilerplate/issues/3470/events","html_url":"https://github.com/aspnetboilerplate/aspnetboilerplate/issues/3470","id":329852209,"node_id":"MDU6SXNzdWUzMjk4NTIyMDk=","number":3470,"title":"How to mapping related collections?","user":{"login":"XelaNimed","id":685832,"node_id":"MDQ6VXNlcjY4NTgzMg==","avatar_url":"https://avatars1.githubusercontent.com/u/685832?v=4","gravatar_id":"","url":"https://api.github.com/users/XelaNimed","html_url":"https://github.com/XelaNimed","followers_url":"https://api.github.com/users/XelaNimed/followers","following_url":"https://api.github.com/users/XelaNimed/following{/other_user}","gists_url":"https://api.github.com/users/XelaNimed/gists{/gist_id}","starred_url":"https://api.github.com/users/XelaNimed/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/XelaNimed/subscriptions","organizations_url":"https://api.github.com/users/XelaNimed/orgs","repos_url":"https://api.github.com/users/XelaNimed/repos","events_url":"https://api.github.com/users/XelaNimed/events{/privacy}","received_events_url":"https://api.github.com/users/XelaNimed/received_events","type":"User","site_admin":false},"labels":[],"state":"closed","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":14,"created_at":"2018-06-06T12:46:40Z","updated_at":"2018-06-12T10:35:30Z","closed_at":"2018-06-12T10:35:30Z","author_association":"NONE","body":"Hello. I'm use:\r\n* Abp version 3.6.2.\r\n* Base framework: .Net Core 2.0.\r\n* ORM framework: EF Core 2.0.\r\n* and [free startup template](http://aspnetboilerplate.com/Templates) for multi-page application with included management pages.\r\n\r\nI had a problem with automatic DTO mapping of an object with collections. The point is that I want to use several interrelated entities as a single entity (something similar to the [DDD aggregate concept](https://martinfowler.com/bliki/DDD_Aggregate.html)). \r\nSo, I have the following data model:\r\n![db-model](https://user-images.githubusercontent.com/685832/41027342-0bcfb66c-6977-11e8-819d-296639460488.jpg)\r\n```csharp\r\npublic class Person : Entity<Guid>, IFullAudited {\r\n  public Person() { }\r\n  public virtual ICollection<PersonAddress> Addresses { get; set; } = \r\n    new HashSet<PersonAddress>();\r\n  public virtual ICollection<PersonEmail> Emails { get; set; } = \r\n    new HashSet<PersonEmail>();\r\n  public virtual ICollection<PersonPhone> Phones { get; set; } = \r\n    new HashSet<PersonPhone>();\r\n  // Other non-important properties of the class are not listed here to save space\r\n}\r\n```\r\nEntities are \"separated\" for the possibility of adding an unlimited number of related entities, in other words is a classical one-to-many relationship. In DTO, these collections are also available, since I want to work with this as with one whole: \r\n```csharp\r\n[AutoMapTo(typeof(Person))]\r\n public class CreatePersonDto : EntityDto<Guid> {\r\n  public List<CreatePersonAddressDto> Addresses { get; set; } = \r\n     new List<CreatePersonAddressDto>();\r\n  public List<CreatePersonEmailDto> Emails { get; set; } = \r\n     new List<CreatePersonEmailDto>();\r\n  public List<CreatePersonPhoneDto> Phones { get; set; } = \r\n     new List<CreatePersonPhoneDto>();\r\n  // Other non-important properties of the class are not listed here to save space\r\n}\r\n```\r\nThe application service looks like this:\r\n```csharp\r\npublic interface IPersonAppService : \r\nIAsyncCrudAppService<PersonDto, Guid, GetAllPersonsDto, CreatePersonDto, UpdatePersonDto, EntityDto<Guid>> { }\r\n\r\npublic class PersonAppService : \r\n  AsyncCrudAppService<Person, PersonDto, Guid, GetAllPersonsDto, CreatePersonDto, UpdatePersonDto, EntityDto<Guid>>, \r\n  IPersonAppService {\r\n\r\n  private readonly IRepository<Person, Guid> _personRepository;\r\n\r\n  public PersonAppService(IRepository<Person, Guid> repository) : base(repository) {\r\n    _personRepository = repository;\r\n  }\r\n\r\n  public override async Task<PersonDto> Create(CreatePersonDto input) {\r\n    CheckCreatePermission();\r\n    var person = ObjectMapper.Map<Person>(input);\r\n    await _personRepository.InsertAsync(person);\r\n    return ObjectMapper.Map<PersonDto>(person);\r\n  }\r\n  \r\n  public override async Task<PersonDto> Update(UpdatePersonDto input) {\r\n      CheckUpdatePermission();\r\n      var person = await _personRepository.GetAsync(input.Id);\r\n      ObjectMapper.Map(input, person);\r\n      return await Get(input);\r\n  }\r\n\r\n  // Other non-important properties of the class are not listed here to save space\r\n}\r\n```\r\nCreation of a new person occurs without problems with all related entities, as expected, for example:\r\n```js\r\nabp.services.app.person.create({\r\n  \"name\" : \"John Doe\",\r\n  \"addresses\" : [\r\n    { \"address\" : \"--private address--\" },\r\n    { \"address\" : \"--business address--\" }\r\n  ],\r\n  \"emails\" : [\r\n    { \"value\" : \"--private email--\" }\r\n  ],\r\n  \"phones\" : [\r\n    { \"number\" : \"--private phone--\" },\r\n    { \"number\" : \"--private fax--\" },\r\n    { \"number\" : \"--private cell phone--\" },\r\n    { \"number\" : \"--business phone--\" },\r\n    { \"number\" : \"--business cell phone--\" },\r\n    { \"number\" : \"--business fax--\" }\r\n  ]\r\n})\r\n.done(function(response){ \r\n    console.log(response); \r\n});\r\n```\r\nbut an error occurs if need to update or delete any related entity:\r\n```\r\nAbp.AspNetCore.Mvc.ExceptionHandling.AbpExceptionFilter - The instance of \r\nentity type 'PersonPhone' cannot be tracked because another instance \r\nwith the same key value for {'Id'} is already being tracked. When attaching \r\nexisting entities, ensure that only one entity instance with a given key \r\nvalue is attached. Consider using \r\n'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the conflicting \r\nkey values.\r\n```\r\nI assume that this happens as a result of overwriting the entity collection when calling `ObjectMapper.Map(input, person);` in application service. After [I asked a question on StackOverflow](https://stackoverflow.com/q/50699613/3129992), it became clear that there is a library that can delete, update and add entities to the collection without overwriting the entire collection - [AutoMapper.Collection](https://github.com/AutoMapper/AutoMapper.Collection). But this library has a dependency on AutoMapper, and the framework uses Abp.AutoMapper, which can not find or use.\r\n\r\nMy question is: is it possible to use AutoMapper.Collection together with Abp.AutoMapper? If this is not possible, then what does the best practice look like to solve this problem?\r\n\r\nThank you in advance for your answers and attention."}}
{"actor":{"display_login":"XelaNimed"}}