Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

destination collection is cleared when mapping collection #114

Closed
xetod opened this issue Nov 17, 2018 · 4 comments
Closed

destination collection is cleared when mapping collection #114

xetod opened this issue Nov 17, 2018 · 4 comments

Comments

@xetod
Copy link

xetod commented Nov 17, 2018

I have two models that have a one to many relation:

public class Make
{
    public int Id { get; set; }
    public string Name { get; set; }
    public ICollection<Model> Models { get; set; }
}

public class Model
{
    public int Id { get; set; }
    public string Name { get; set; }
    public Make Make { get; set; }
    public int MakeId { get; set; }
}

and the DTO as follows:

public class MakeDto
{
    public int Id { get; set; }
    public string Text { get; set; }
    public ICollection<Models> Models { get; set; }
}

I'm using Automapper.Collection to map DTO in update operation:

var config = new MapperConfiguration(cfg =>
    {
        cfg.AddCollectionMappers();
    });
var mapper = config.CreateMapper();

mapper.Map<MakeDto, Make>(makeDto, make);

the issue is I don't know why Automapper.Collection first clears destination collection and then again add new ones, no matter entities in source collection are new, removed or updated.

@Tasteful
Copy link
Contributor

I can't see that you configure the collection mapping for the entity.

If you try to register the equality comparison when you register the type map like the following. Then AutoMapper.Collection knows how the object should be compared. If this step is omitted the standard collection mapping from AutoMapping is used.

var config = new MapperConfiguration(cfg =>
    {
        cfg.AddCollectionMappers();
        cfg.CreateMap<MakeDto, Make>()
                    .EqualityComparison((dto, entity) => dto.Id == entity.Id);

    });
var mapper = config.CreateMapper();

@xetod
Copy link
Author

xetod commented Nov 17, 2018

when I want to map in my action I got this error:

InvalidOperationException: The instance of entity type 'Model' cannot be tracked because another instance with the same key value for {'Id'} is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the conflicting key values.

the action code as follows:

        [AllowAnonymous]
        [HttpPut("{id}")]
        public IActionResult UpdateMake(int id, [FromBody]MakeDto makeDto)
        {
            var make = _context.Makes
                .Include(m => m.Models)
                .SingleOrDefault(m => m.Id == id);

            var mapper = new MapperConfiguration(
                cfg =>
                {
                    cfg.AddCollectionMappers();
                    cfg.CreateMap<MakeDto, Make>()
                        .EqualityComparison((dto, entity) => dto.Id == entity.Id);
                })
                .CreateMapper();            

            mapper.Map<MakeDto, Make>(makeDto, make);

            _context.SaveChanges();

            return Ok(make);
        }

and the JSON that I'm sending in Postman is as follows and I got the above error (Model table has two records with Id 1 and 2 and Make table has one record with Id 1):

{
	id: 1,
	Name: "Make 1",
	Models: [
		{
			Id: 1,
			Name: "Model 1"
		},
		{
			Id: 2,
			Name: "Model 2"
		}
	]
}

but if I omit the Id of table Model in JSON, Automapper.Collection removes all records on table Model and save the records again..

@TylerCarlson1
Copy link
Member

You need to do equality comparison on the items inside the collections. Model and Models. (I'm asusming they are two distinct classes)
cfg.CreateMap<Model, Models>().EqualityComparison((dto, entity) => dto.Id == entity.Id);
Adding this to Automapper Configuration should fix the problem.

Also if it's a misspelled and they are the same class this might still work, although it's not an officially supported case for AutoMapper. Recommendation would be to make a ModelDto and map to that.

@xetod
Copy link
Author

xetod commented Nov 20, 2018

It's working now. Many Thanks.

@xetod xetod closed this as completed Nov 20, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants