简体   繁体   中英

EF and Automapper

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?

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.

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... :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM