I'm working on ASP.NET Boilerplate. I have the problem where I try to get a record from a table called Buildings
and make an update on it. I get the record from database by:
var buildingApp = _buildingsAppService.getBuildingsById(buildingInput);
And after that, I make some changes on the data as follows:
buildingApp.streetName = Request["buildingaddress"];
buildingApp.isInHoush = Convert.ToBoolean(Request["buildingOutput.isInHoush"]);
buildingApp.houshName = Request["HoushName"];
And then copy the buildingApp
to another object, which has the same properties, in order to pass the new object to update
method as follows:
var updateBuildingInput = new UpdateBuidlingsInput()
{
Id = buildingApp.Id,
buildingID = buildingApp.buildingID,
numOfBuildingUnits = buildingApp.numOfBuildingUnits,
numOfFloors = buildingApp.numOfFloors,
streetName = buildingApp.streetName,
buildingNo = buildingApp.buildingNo,
neighborhoodID = buildingApp.neighborhoodID,
buildingTypeID = buildingApp.buildingTypeID,
GISMAP = buildingApp.GISMAP,
houshProperty = buildingApp.houshProperty,
houshName = buildingApp.houshName,
X = buildingApp.X,
Y = buildingApp.Y,
buildingName = buildingApp.buildingName,
isInHoush = buildingApp.isInHoush,
buildingUsesID = buildingApp.buildingUsesID
};
And the update
method is as follows:
_buildingsAppService.update(updateBuildingInput);
The problem is when it executes the previous line, I get the following error:
System.InvalidOperationException: 'Attaching an entity of type 'TaawonMVC.Models.Buildings' failed because another entity of the same type already has the same primary key value. This can happen when using the 'Attach' method or setting the state of an entity to 'Unchanged' or 'Modified' if any entities in the graph have conflicting key values. This may be because some entities are new and have not yet received database-generated key values. In this case use the 'Add' method or the 'Added' entity state to track the graph and then set the state of non-new entities to 'Unchanged' or 'Modified' as appropriate.'
I can see that when I initialize the object updateBuildingInput
manually, the update
method runs without error. But when it depends on the object obtained from database using buildingApp
, the error happens. It seems like the get
method gets data from database and keeps holding on to the record from database, and when I try to update the same record, the conflict happens. This is the whole action where all of get
and update
happens:
public ActionResult UpdateApplication (UpdateApplicationsInput model)
{
var updateApplication = new UpdateApplicationsInput();
updateApplication.buildingId = Convert.ToInt32(Request["buildingnumber"]);
updateApplication.buildingUnitId = Convert.ToInt32(Request["dropDownBuildingUnitApp"]);
//==== get building and unit related to application for update ======
var buildingInput = new GetBuidlingsInput()
{
Id = updateApplication.buildingId
};
var buildingUnitInput = new GetBuildingUnitsInput()
{
Id = updateApplication.buildingUnitId
};
var buildingApp = _buildingsAppService.getBuildingsById(buildingInput);
var buildingUnitApp = _buildingUnitsAppService.GetBuildingUnitsById(buildingUnitInput);
buildingApp.streetName = Request["buildingaddress"];
buildingApp.isInHoush = Convert.ToBoolean(Request["buildingOutput.isInHoush"]);
buildingApp.houshName = Request["HoushName"];
// buildingUnitApp.BuildingId = updateApplication.buildingId;
buildingUnitApp.ResidenceStatus = Request["residentstatus"];
// copy object getBuildingUnitInput to updateBuildingUnitInput
var updateBuildingUnitInput = new UpdateBuildingUnitsInput()
{
BuildingId = buildingUnitApp.BuildingId,
ResidentName = buildingUnitApp.ResidentName,
ResidenceStatus = buildingUnitApp.ResidenceStatus,
NumberOfFamilyMembers = buildingUnitApp.NumberOfFamilyMembers,
Floor = buildingUnitApp.Floor,
UnitContentsIds = buildingUnitApp.UnitContentsIds
};
//============================================
// copy object from getBuildingOutput to updateBuildingInput
var updateBuildingInput = new UpdateBuidlingsInput()
{
Id = buildingApp.Id,
buildingID = buildingApp.buildingID,
numOfBuildingUnits = buildingApp.numOfBuildingUnits,
numOfFloors = buildingApp.numOfFloors,
streetName = buildingApp.streetName,
buildingNo = buildingApp.buildingNo,
neighborhoodID = buildingApp.neighborhoodID,
buildingTypeID = buildingApp.buildingTypeID,
GISMAP = buildingApp.GISMAP,
houshProperty = buildingApp.houshProperty,
houshName = buildingApp.houshName,
X = buildingApp.X,
Y = buildingApp.Y,
buildingName = buildingApp.buildingName,
isInHoush = buildingApp.isInHoush,
buildingUsesID = buildingApp.buildingUsesID
};
//======================================================
updateApplication.Id = Convert.ToInt32(Request["applicationId"]);
updateApplication.fullName = model.fullName;
updateApplication.phoneNumber1 = model.phoneNumber1;
updateApplication.phoneNumber2 = model.phoneNumber2;
updateApplication.isThereFundingOrPreviousRestoration = model.isThereFundingOrPreviousRestoration;
updateApplication.isThereInterestedRepairingEntity = model.isThereInterestedRepairingEntity;
updateApplication.housingSince = model.housingSince;
updateApplication.previousRestorationSource = model.previousRestorationSource;
updateApplication.interestedRepairingEntityName = model.interestedRepairingEntityName;
updateApplication.PropertyOwnerShipId = Convert.ToInt32(Request["PropertyOwnerShip"]);
updateApplication.otherOwnershipType = model.otherOwnershipType;
updateApplication.interventionTypeId = Convert.ToInt32(Request["interventionTypeName"]);
updateApplication.otherRestorationType = model.otherRestorationType;
updateApplication.propertyStatusDescription = model.propertyStatusDescription;
updateApplication.requiredRestoration = model.requiredRestoration;
updateApplication.buildingId = Convert.ToInt32(Request["buildingnumber"]);
updateApplication.buildingUnitId = Convert.ToInt32(Request["dropDownBuildingUnitApp"]);
// ==== get of restoration types which it is multi select drop down list ======
var restorationTypes = Request["example-getting-started"];
string[] restorationTypesSplited = restorationTypes.Split(',');
byte[] restorationTypesArray = new byte[restorationTypesSplited.Length];
for (var i = 0; i < restorationTypesArray.Length; i++)
{
restorationTypesArray[i] = Convert.ToByte(restorationTypesSplited[i]);
}
updateApplication.restorationTypeIds = restorationTypesArray;
// ====== end of RestorationTypes
_buildingsAppService.update(updateBuildingInput);
_applicationsAppService.Update(updateApplication);
// _buildingUnitsAppService.Update(updateBuildingUnitInput);
// ==== get list of applications ==============
var applicationsUpdate = _applicationsAppService.getAllApplications();
var applicationsViewModel = new ApplicationsViewModel()
{
Applications = applicationsUpdate
};
return View("Applications", applicationsViewModel);
}
How ASP.NET Boilerplate template, which I use, makes CRUD Operation to database:
public class BuildingsManager : DomainService, IBuildingsManager
{
private readonly IRepository<Buildings> _repositoryBuildings;
public BuildingsManager(IRepository<Buildings> repositoryBuildings)
{
_repositoryBuildings = repositoryBuildings;
}
// create new building in table buildings .
public async Task<Buildings> create(Buildings entity)
{
var building = _repositoryBuildings.FirstOrDefault(x => x.Id == entity.Id);
if(building!=null)
{
throw new UserFriendlyException("Building is already exist");
}
else
{
return await _repositoryBuildings.InsertAsync(entity);
}
}
// delete a building from buildings table .
public void delete(int id)
{
try
{
var building = _repositoryBuildings.Get(id);
_repositoryBuildings.Delete(building);
}
catch (Exception)
{
throw new UserFriendlyException("Building is not exist");
}
}
public IEnumerable<Buildings> getAllList()
{
return _repositoryBuildings.GetAllIncluding(b => b.BuildingType, n => n.NeighboorHood,u=>u.BuildingUses);
}
public Buildings getBuildingsById(int id)
{
return _repositoryBuildings.Get(id);
}
public void update(Buildings entity)
{
_repositoryBuildings.Update(entity);
}
}
How can I solve this problem? Many thanks for help.