0

I have the following domain classes:

public class ApplicationDriverLicenseDomain
{
    public ApplicationDriverLicenseDomain()
    {
        CDLTypes = new List<ApplicationLicenseCDLTypeDomain>();
        Endorsements = new List<ApplicationLicenseEndorsementDomain>();
    }

    public string Name { get; set; }
    public string MaidenName { get; set; }

    public virtual List<ApplicationLicenseCDLTypeDomain> CDLTypes { get; set; }

    public virtual List<ApplicationLicenseEndorsementDomain> Endorsements { get; set; }
}

public class ApplicationLicenseCDLTypeDomain
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class ApplicationLicenseEndorsementDomain
{
    public int Id { get; set; }
    public string Name { get; set; }
}

and EF classes:

[Table("ApplicationLicenseCDLTypes")]
public partial class ApplicationLicenseCDLType
{
    public ApplicationLicenseCDLType()
    {
        ApplicationDriverLicenses = new HashSet<ApplicationDriverLicense>();
    }

    public int Id { get; set; }
    [Required]
    [StringLength(256)]
    public string Name { get; set; }

    public virtual ICollection<ApplicationDriverLicense> ApplicationDriverLicenses { get; set; }

}

[Table("ApplicationLicenseEndorsements")]
public partial class ApplicationLicenseEndorsement
{
    public ApplicationLicenseEndorsement()
    {
        ApplicationDriverLicenses = new HashSet<ApplicationDriverLicense>();
    }

    public int Id { get; set; }
    [Required]
    [StringLength(256)]
    public string Name { get; set; }

    public virtual ICollection<ApplicationDriverLicense> ApplicationDriverLicenses { get; set; }

}

[Table("ApplicationDriverLicenses")]
public partial class ApplicationDriverLicense
{
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
    public ApplicationDriverLicense()
    {
        CDLTypes = new HashSet<ApplicationLicenseCDLType>();
        Endorsements = new HashSet<ApplicationLicenseEndorsement>();
    }

    [Required]
    [StringLength(256)]
    public string Name { get; set; }

    [Key, ForeignKey("Driver")]
    public int DriverId { get; set; }
    public virtual ApplicationDriver Driver { get; set; }


    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<ApplicationLicenseCDLType> CDLTypes { get; set; }

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<ApplicationLicenseEndorsement> Endorsements { get; set; }

}

Also, there are 2 additional tables to store selected CDLTypes/Endorsements

        modelBuilder.Entity<ApplicationDriverLicense>()
            .HasMany(e => e.CDLTypes)
            .WithMany(e => e.ApplicationDriverLicenses)
            .Map(m => m.ToTable("ApplicationDriverLicenseCDLTypes").MapLeftKey("DriverId").MapRightKey("TypeId"));


        modelBuilder.Entity<ApplicationDriverLicense>()
            .HasMany(e => e.Endorsements)
            .WithMany(e => e.ApplicationDriverLicenses)
            .Map(m => m.ToTable("ApplicationDriverLicenseEndorsements").MapLeftKey("DriverId").MapRightKey("TypeId"));

Then I map domain classes to EF classes:

        CreateMap<ApplicationDriverLicenseDomain, Infrastructure.Asset.ApplicationDriverLicense>();
        CreateMap<ApplicationLicenseEndorsementDomain, Infrastructure.Asset.ApplicationLicenseEndorsement>();
        CreateMap<ApplicationLicenseCDLTypeDomain, Infrastructure.Asset.ApplicationLicenseCDLType>();

but when I try to add records to DB:

    public async Task AddApplicationAsync(ApplicationDriverDomain model)
    {
        Infrastructure.Asset.ApplicationDriver driver = mapper.Map<Infrastructure.Asset.ApplicationDriver>(model);
        db.ApplicationDrivers.Add(driver);
        await db.SaveChangesAsync();
    }

it adds new records for CDL types/Endorsements instead of to get current. As I understand, I should do "Attach". How to do it with Automapper rules?

Oleg Sh
  • 8,496
  • 17
  • 89
  • 159
  • 1
    As a rule, you wouldn't. Automapper's job is just to create new instances of objects. It's up to the caller to decide what to do with them, in this case, attaching to a `DbSet`. Unless I'm missing something? – DiskJunky Oct 03 '17 at 13:41
  • @DiskJunky, you are not missing something. I just want to have all rules in one place. – Oleg Sh Oct 03 '17 at 13:50
  • 1
    Personally I wouldn't consider it appropriate to put that rule in with the Automapper bindings as there'll likely be times when you want to map but don't want to attach (e.g, when you actually *want* to insert). It doesn't strike me as a good idea – DiskJunky Oct 03 '17 at 13:51
  • I agree. Also, "map and then attach" is not a "rule", it's a process description. A "rule" is abstract and doesn't prescribe any implementation. What you're after violates *Single Responsibility*. – Gert Arnold Oct 03 '17 at 14:11
  • 1
    https://github.com/AutoMapper/AutoMapper.Collection – Lucian Bargaoanu Oct 03 '17 at 14:15

2 Answers2

1

While I agree with @DiskJunky comment above, to address the issue at hand: In your ApplicationDriverLicense class you have virtual properties for Endorsements and CDLTypes types. Auto-mapper is populating these properties, and since they are not attached to context, EF creates new records for them.

I would suggest having Auto-Mapper Ignore mapping these virtual properties, and leave them empty, and that should resolve your issue.

farzaaaan
  • 410
  • 3
  • 9
0

I implemented it by the way:

    public async Task AddApplicationAsync(ApplicationDriverDomain model)
    {
        Infrastructure.Asset.ApplicationDriver driver = mapper.Map<Infrastructure.Asset.ApplicationDriver>(model);

        var cdlTypes = driver.CommercialLicense.CDLTypes;
        foreach (var type in cdlTypes)
        {
            db.ApplicationLicenseCDLTypes.Attach(type);
        }

        var endorsements = driver.CommercialLicense.Endorsements;
        foreach (var endorsement in endorsements)
        {
            db.ApplicationLicenseEndorsements.Attach(endorsement);
        }

        db.ApplicationDrivers.Add(driver);
        await db.SaveChangesAsync();
    }

so, I did not reach my purpose to describe all rules in one place... :)

Oleg Sh
  • 8,496
  • 17
  • 89
  • 159