使用AutoMapper.Collection映射集合时重复创建数据库记录而非更新的问题求助
Hey there! I see you're stuck getting AutoMapper.Collection to update existing database records instead of creating new ones every time. Let's walk through the most common fixes for this issue:
1. Make Sure You're Using the Right Collection Mapping Approach
AutoMapper.Collection's update magic only kicks in when you map your source collection onto an existing destination collection (the one you pull from your database)—not when you create a brand new collection from scratch.
❌ Wrong way (creates new records):
var newPhotos = _mapper.Map<List<Photo>>(photoUpdateDtos); _context.Photos.AddRange(newPhotos);
✅ Correct way (updates existing records):
// First fetch the existing records from your database var existingPhotos = _context.Photos.Where(p => p.UserId == targetUserId).ToList(); // Map the source DTOs directly onto the existing collection _mapper.Map(photoUpdateDtos, existingPhotos); // Now SaveChanges() will handle updates, inserts, and deletes automatically _context.SaveChanges();
2. Fix Your Equality Comparison (Handle Nulls!)
Your current equality checks don't account for null values in PublicId or Name. If either property is null, you'll get a NullReferenceException, and AutoMapper will fall back to reference equality (which won't match existing database records, since they're separate object instances).
Update your profile to use safe, case-insensitive comparisons:
public class UserMappingProfile : Profile { public UserMappingProfile() { CreateMap<PhotoToUpdateDto, Photo>() .EqualityComparison((src, dest) => string.Equals(src.PublicId, dest.PublicId, StringComparison.OrdinalIgnoreCase)); CreateMap<SocialHandles, SocialHandleDto>() .ReverseMap() .EqualityComparison((src, dest) => string.Equals(src.Name, dest.Name, StringComparison.OrdinalIgnoreCase)); } }
string.Equals with StringComparison.OrdinalIgnoreCase is cleaner than manual ToLower() calls and handles nulls gracefully.
3. Ensure Your Profile Is Loaded Correctly
Double-check that AutoMapper is actually scanning and loading your UserMappingProfile. Sometimes explicitly specifying the profile in the AddAutoMapper call avoids assembly scanning hiccups:
services.AddAutoMapper(cfg => { cfg.AddCollectionMappers(); }, typeof(UserMappingProfile), typeof(Startup));
This tells AutoMapper to prioritize your profile alongside any other mappings in the Startup assembly.
4. Check Version Compatibility
Make sure your AutoMapper and AutoMapper.Collection NuGet packages are compatible. Mismatched major versions often break collection mapping functionality. Head to NuGet and ensure both packages are on the latest compatible versions (AutoMapper.Collection typically follows AutoMapper's major versioning).
5. Enable Delete Behavior (If Needed)
If you also need to remove records that aren't present in your source collection, add this to your mapping config to mark missing records for deletion:
CreateMap<PhotoToUpdateDto, Photo>() .EqualityComparison(/* your existing logic */) .ForAllOtherMembers(opt => opt.Condition((src, dest, srcMember) => srcMember != null)); // Optional: for partial updates
Just make sure your DbContext is tracking the existing collection so deletes are detected when you call SaveChanges().
Give these steps a shot, and let me know if you're still running into issues!
内容的提问来源于stack exchange,提问作者Taryosky

