Ardalan Shahgholi Ardalan Shahgholi - 2 months ago 10
C# Question

Entity Framework Can Not Save My Change

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.

Answer

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();
Comments