2
votes

I'm using the following design:

System architecture

I'm using AutoMapper for the domain/DTO conversions (both ways), Entity Framework Code First, and SQL Server 2012.

Each table has a field named RowVersion of type timestamp in order to check updates.

I'm using a DTO layer because my domain objects can't be serialized in WCF services, and I have a cycle in my domain layer.

Anyway, my problem is that when create a Bank (one table with a single page in the UI) I copy the values (BankCode, BankName) into BankDTO and in my service layer I convert BankDTO to BankDomain (the entity domain object for Bank) using AutoMapper, then call SaveChange.

That works, and I can update the bank too.

But when I edit one Bank and a bank branch, then convert BankDTO TO BankDomain and call SaveChange, that doesn't work. If I map BankDTO to BankDomain without AutoMapper, that works and the update is performed.

My BankDTO looks like this:

[Serializable]
public class BankModel
{

    public BankModel()
    {
        this.BankBranches = new List<BankBranchModel>();
    }
    public int? Id { get; set; }
    public byte[] RowVersion { get; set; } 
    public decimal BankCode { get; set; } 
    public string BankName { get; set; } 
    public string LatinCode { get; set; }

    public virtual ICollection<BankBranchModel> BankBranches { get; set; }

}

And the BankBranch DTO:

[Serializable]
public class BankBranchModel
{

    public BankBranchModel()
    {

    }

    public int BankId { get; set; }
    public decimal BranchCode { get; set; }
    public string BranchName { get; set; } 
    public int? ExecutiveUnitId { get; set; }
    public int? Id { get; set; } 
    public byte[] RowVersion { get; set; } 
    public BankModel Bank { get; set; } 

}

BankDomain:

public class Bank : BaseEntity
{
    public Bank()
    {
        this.BankBranches = new List<BankBranch>();     
    }
    public decimal BankCode { get; set; } 
    public string BankName { get; set; } 
    public string LatinCode { get; set; }

    public virtual ICollection<BankBranch> BankBranches { get; set; }
}

And BankBranchDomain:

public class BankBranch : BaseEntity
{
    public BankBranch()
    {
    }
    public int BankId { get; set; } 
    public decimal BranchCode { get; set; } 
    public string BranchName { get; set; } 

    public virtual Bank  Bank { get; set; }    
}

The SQL table is created like this:

CREATE TABLE [global].[Bank](
[Id] [int] NOT NULL,
[RowVersion] [timestamp] NOT NULL,
[BankCode] [numeric](18, 0) NOT NULL,
[BankName] [varchar](20) NOT NULL,
[LatinCode] [varchar](3) NOT NULL,
    CONSTRAINT [PKBnk] PRIMARY KEY CLUSTERED 
    (
        [Id] ASC
    ) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,      
            ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
 ) ON [PRIMARY]

CREATE TABLE [global].[BankBranch](
[Id] [int] NOT NULL,
[RowVersion] [timestamp] NOT NULL,
[BranchCode] [numeric](18, 0) NOT NULL,
[BranchName] [varchar](100) NOT NULL,
[BankId] [int] NOT NULL,
[ExecutiveUnitId] [int] NULL,
    CONSTRAINT [PK_BankBranch] PRIMARY KEY CLUSTERED 
    (
        [Id] ASC
    ) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,  
            ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

And the update code:

using (var db = new AndishmandTestContext())
{
    Mapper.CreateMap<BankModel, Bank>();
    Mapper.CreateMap<Bank, BankModel>();

    Mapper.CreateMap<BankBranchModel, BankBranch>();
    Mapper.CreateMap<BankBranch, BankBranchModel>();

    var oldb = db.Banks.Include("BankBranches").Where(b => b.Id == 1);
    Bank bank = oldb.FirstOrDefault();
    BankModel bankmodel = new BankModel();
    Mapper.Map(bank, bankmodel);
}

After changing the BankModel in the UI layer, this code executes in the service layer:

var Newb = db.Banks.Include("BankBranches").Where(b => b.Id == 1);
Bank newbank = Newb.FirstOrDefault();
Mapper.Map(bankmodel, newbank);

Then the change is saved in the business layer:

db.SaveChanges();

If I map BankDto and BankBranchDto in BankDomain and BankBranchDomain instead of using Mapper.Map, then SaveChanges works - but I have to use AutoMapper.

2
"It not work" isn't nearly enough information about what actually happens. Is there an exception? Does it go through without an exception but just not alter any data in the database? Also note that you don't need to make each sentence into its own paragraph. - Jon Skeet
It is very confusing that you use two names for your objects. Please, stick to the class names only. And again, it is not clear what doesn't work. - Gert Arnold
Jon Skeet : it was done but any data in database change. - Ardalan Shahgholi

2 Answers

2
votes

You need to add object or values first which you have changed then save the changes.

  db.Banks.AddObject(---your object name or value which you want to add---);
   db.SaveChanges();
2
votes

I finded my answer. I changeed my map and it woked

like this

            Mapper.CreateMap<BankModel, Bank>().ForMember(x => x.BankBranches, opt => opt.Ignore());
            //Mapper.CreateMap<BankModel, Bank>();
            Mapper.CreateMap<Bank, BankModel>();

            Mapper.CreateMap<BankBranchModel, BankBranch>().ForMember(x => x.Bank, opt => opt.Ignore());
            //Mapper.CreateMap<BankBranchModel, BankBranch>();
            Mapper.CreateMap<BankBranch, BankBranchModel>();

And then i most modify my domains like this

              //update bankdomain
            Mapper.Map(bankmodel, newbank);

            //Update bank branchdomain
            newbank.BankBranches.ToList().ForEach(bb => Mapper.Map(bankmodel.BankBranches.First(c => c.Id == bb.Id), bb));

            //Delete branchdomain
            foreach (var bBmodel in bankmodel.BankBranches.Where(bB => bB.IsDeleted == true))
            {
                newbank.BankBranches.Remove(newbank.BankBranches.Where(bb => bb.Id == bBmodel.Id).First());
            }

            //Add branchdomain
            foreach (var bBM in bankmodel.BankBranches.Where(c => c.Id == null))
            {
                newbank.BankBranches.Add(Mapper.Map<BankBranch>(bBM));
            }

and then

db.SaveChanges();