Better Way to Create an Audit Trail Using Entity Framework - entity-framework

I have looked through many examples of creating an audit trail using the Entity Framework and have yet to find anything that works for me. There must be a slick/terse way to do it by simply overriding SaveChanges in the DB Context and using the ChangeTracker...issues I have run into are things such as when adding (creating) an entity it does not have an ID until after you save it and when you save it, it seems to blast what's in the change tracker. Anyway, I have got an audit trail working but it's ugly as hell and I was looking for help in simplifying this and making it such that I don't have to add on to a horrible if-then every time I add an entity! Any and all help appreciated.
public bool CreateRecord(object o)
{
Audit audit = new Audit()
{
ChangeTypeID = (int)Audit.ChangeType.CREATE,
TimeStamp = GetCurrentDateTime(),
RecordClass = o.GetType().ToString(),
NewValue = "",
ReasonForChange = "Record Creation"
};
if (o.GetType() == typeof(Permission))
{
Permission x = (Permission)o;
audit.OriginalValue = x.ToString();
Permissions.Add(x);
SaveChanges();
audit.RecordID = x.ID;
}
else if (o.GetType() == typeof(User))
{
User x = (User)o;
audit.OriginalValue = x.ToString();
Users.Add(x);
SaveChanges();
audit.RecordID = x.ID;
}
else if (o.GetType() == typeof(LogIn))
{
LogIn x = (LogIn)o;
audit.OriginalValue = x.ToString();
LogIns.Add(x);
SaveChanges();
audit.RecordID = x.ID;
}
else if (o.GetType() == typeof(Marker))
{
Marker x = (Marker)o;
audit.OriginalValue = x.ToString();
Markers.Add(x);
SaveChanges();
audit.RecordID = x.ID;
}
else if (o.GetType() == typeof(Method))
{
Method x = (Method)o;
audit.OriginalValue = x.ToString();
Methods.Add(x);
SaveChanges();
audit.RecordID = x.ID;
}
else if (o.GetType() == typeof(Sample))
{
Sample x = (Sample)o;
audit.OriginalValue = x.ToString();
Samples.Add(x);
SaveChanges();
audit.RecordID = x.ID;
}
else if (o.GetType() == typeof(Run))
{
Run x = (Run)o;
audit.OriginalValue = x.ToString();
Runs.Add(x);
SaveChanges();
audit.RecordID = x.ID;
}
else if (o.GetType() == typeof(XYDataSet))
{
XYDataSet x = (XYDataSet)o;
audit.OriginalValue = x.ToString();
XYDataSets.Add(x);
SaveChanges();
audit.RecordID = x.ID;
}
else
{
return false;
}
// Save audit record
audit.UserID = ((App)Application.Current).GetCurrentUserID();
Audits.Add(audit);
SaveChanges();
return true;
}

I am assuming that all of the entities belongs to same project/assembly, so you can try something like that and notice that this code doesn't tested, modifications might be needed.
public bool CreateRecord(object o)
{
Audit audit = new Audit()
{
ChangeTypeID = (int)Audit.ChangeType.CREATE,
TimeStamp = GetCurrentDateTime(),
RecordClass = o.GetType().ToString(),
NewValue = "",
ReasonForChange = "Record Creation"
};
var entityType = Assembly.GetAssembly(typeof(Permission)).GetTypes().Where(x => x == o.GetType())
.FirstOrDefault(); // Determine the desired entity (assumed all of the entities belongs to same project/assembly)
if (entityType != null)
{
var convertedObject = Convert.ChangeType(o, entityType); // Convert object to entity
audit.OriginalValue = convertedObject.ToString();
var entity = yourContext.Set(entityType).Add(convertedObject); // Get DbSet for casted entity
SaveChanges();
audit.RecordID = x.ID;
}
else
{
return false;
}
// Save audit record
audit.UserID = ((App)Application.Current).GetCurrentUserID();
Audits.Add(audit);
SaveChanges();
return true;
}

Related

EF Core 3.x: duplicate value

I have the following code:
public class DeviceVerizon
{
public int DeviceId { get; set; }
public string InternalDeviceId { get; set; }
}
and
public class DeviceVerizonMap : IEntityTypeConfiguration<DeviceVerizon>
{
public void Configure(EntityTypeBuilder<DeviceVerizon> builder)
{
builder.ToTable(nameof(DeviceVerizon));
builder.HasKey(d => d.DeviceId);
builder.HasIndex(v => v.InternalDeviceId).IsUnique();
builder.HasOne(o => o.Device)
.WithOne(o => o.VerizonData)
.HasForeignKey<DeviceVerizon>(a => a.DeviceId)
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
;
}
}
so, InternalDeviceId is just unique index.
some code change InternalDeviceId for existing record and add new record with the previous InternalDeviceId.
So, localDevice.VerizonData.InternalDeviceId = 1420531689
I update it for new (remoteDevice.VerizonData.InternalDeviceId = '111111111')
localDevice.VerizonData = remoteDevice.VerizonData;
_context.Devices.Update(localDevice);
then add new record with remoteDevice.VerizonData.InternalDeviceId = 1420531689:
_context.Devices.Add(remoteDevice);
and after it I call:
await _context.SaveChangesAsync();
but I get an exception:
Cannot insert duplicate key row in object 'dbo.DeviceVerizon' with
unique index 'IX_DeviceVerizon_InternalDeviceId'. The duplicate key
value is (1420531689).
The full code:
foreach (var remoteDevice in remoteVerizonDevices)
{
var localDevice = allLocalDevicesWithIMEI.Where(a =>
(string.IsNullOrWhiteSpace(remoteDevice.IMEI)
&& a.VerizonData != null
&& a.VerizonData.InternalDeviceId == remoteDevice.VerizonData.InternalDeviceId
&& a.IMSI == remoteDevice.IMSI && a.ICCID == remoteDevice.ICCID)
|| a.IMEI == remoteDevice.IMEI).FirstOrDefault();
if (localDevice != null) // device with such imei already exists or IMEI is empty on Verizon, but InternalDeviceId is the same and ICCID with IMSI are the same
{
var verizonStatus = remoteDevice.VerizonData.State.ConvertToDeviceStatusFromVerizonStatus();
var existingRequest = _context.VerizonRequests.Where(a => a.DeviceId == localDevice.Id && a.Result == VerizonRequestResult.Pending).FirstOrDefault();
if (verizonStatus == DeviceStatus.Active && remoteDevice.IsVerizonLastActiveMoreThanDays(60))
{
// existing request for this device does not exist, create new
if (existingRequest == null)
{
localDevice.Status = DeviceStatus.PendingSuspend;
localDevice.DateStatusChanging = DateTime.UtcNow;
localDevice.LastStatusChangeSource = DeviceStatusChangeSource.Verizon;
// create verizon request to change status, because device is offline more than 60 days
verizonSuspensionList.Add(localDevice.Id);
}
}
else
{
// Is Verizon status of device is different than locally?
if (localDevice.Status != verizonStatus)
{
// check whether we have active verizon request, if not, then
if (existingRequest == null)
{
// device is suspended on suremdm, we should suspend on Verizon
if (localDevice.Status == DeviceStatus.Suspended
&& verizonStatus == DeviceStatus.Active)
{
if (localDevice.Tablet != null && localDevice.Tablet.TabletGroup.GroupName == SpecialSureMdmGroups.Suspended)
verizonSuspensionList.Add(localDevice.Id);
}
else if (localDevice.Status != DeviceStatus.Suspended && verizonStatus == DeviceStatus.Suspended)
{
// if device is suspended on verizon, we need to suspend on SureMdm
localDevice.Status = DeviceStatus.PendingSuspend;
localDevice.DateStatusChanging = DateTime.UtcNow;
localDevice.LastStatusChangeSource = DeviceStatusChangeSource.Verizon;
if (localDevice.Tablet != null)
{
localDevice.Tablet.SuspensionDate = DateTime.UtcNow;
sureMdmSuspensionList.Add(new Core.Dto.DeviceManagement.SureMdm.SureMdmMoveDeviceToSuspendedGroupDto
{
TabletId = localDevice.Tablet.TabletId,
CurrentGroupId = localDevice.Tablet.TabletGroupId
});
}
}
else
{
// other cases that device on verizon has different status, that locally
VerizonStatusIsDifferentEvent?.Invoke(
remoteDevice: remoteDevice,
verizonStatus: remoteDevice.VerizonData.State.ConvertToDeviceStatusFromVerizonStatus(),
localStatus: localDevice.Status);
}
}
}
}
var changes = DeviceIsChanged(remoteDevice, localDevice);
if (changes != null && changes.Count > 0)
modifiedDevices.Add((localDevice, changes));
var continueToUpdate = true;
// if verizon data does not exist, add it
if (localDevice.VerizonData == null)
{
var existingInternalVerizonDeviceIdRecord = allDeviceVerizons.Where(a => a.InternalDeviceId == remoteDevice.VerizonData.InternalDeviceId).FirstOrDefault();
if (existingInternalVerizonDeviceIdRecord != null)
{
DeviceWithTheSameVerizonDeviceIdAlreadyExistsEvent?.Invoke(remoteDevice: remoteDevice,
localDevice: existingInternalVerizonDeviceIdRecord.Device,
verizonDeviceId: remoteDevice.VerizonData.InternalDeviceId);
continueToUpdate = false;
}
}
if (continueToUpdate)
{
localDevice.VerizonData = remoteDevice.VerizonData;
if (!string.IsNullOrWhiteSpace(remoteDevice.ICCID))
localDevice.ICCID = remoteDevice.ICCID;
localDevice.EID = remoteDevice.EID;
localDevice.ESN = remoteDevice.ESN;
if (!string.IsNullOrWhiteSpace(remoteDevice.IMSI))
localDevice.IMSI = remoteDevice.IMSI;
if (!string.IsNullOrWhiteSpace(remoteDevice.MDN))
localDevice.MDN = remoteDevice.MDN;
localDevice.MEID = remoteDevice.MEID;
localDevice.MIN = remoteDevice.MIN;
localDevice.MSISDN = remoteDevice.MSISDN;
localDevice.SKU = remoteDevice.SKU;
localDevice.SyncVerizon = true;
if (string.IsNullOrWhiteSpace(localDevice.Name))
localDevice.Name = localDevice.IMEI;
if (!localDevice.DeviceModelId.HasValue)
{
var verizonGroup = allVerizonGroups.Where(a => a.VerizonGroupName == remoteDevice.VerizonData.GroupName).FirstOrDefault();
if (!verizonGroup.DeviceModelId.HasValue)
VerizonGroupIsNotLinkedWithDeviceModelEvent?.Invoke(remoteDevice);
else
localDevice.DeviceModelId = verizonGroup.DeviceModelId;
}
_context.Devices.Update(localDevice);
}
}
else
{
// validate by Internal Verizon DeviceId
var existingInternalVerizonDeviceIdRecord = allDeviceVerizons.Where(a => a.InternalDeviceId == remoteDevice.VerizonData.InternalDeviceId).FirstOrDefault();
if (existingInternalVerizonDeviceIdRecord != null)
{
DeviceWithTheSameVerizonDeviceIdAlreadyExistsEvent?.Invoke(remoteDevice: remoteDevice,
localDevice: existingInternalVerizonDeviceIdRecord.Device,
verizonDeviceId: remoteDevice.VerizonData.InternalDeviceId);
}
else
{
// add new record
if (!string.IsNullOrWhiteSpace(remoteDevice.IMEI))
remoteDevice.Name = remoteDevice.IMEI;
else if (!string.IsNullOrWhiteSpace(remoteDevice.VerizonData.PrimaryPlaceOfUseFirstName) || !string.IsNullOrWhiteSpace(remoteDevice.VerizonData.PrimaryPlaceOfUseLastName))
remoteDevice.Name = $"{remoteDevice.VerizonData.PrimaryPlaceOfUseFirstName} {remoteDevice.VerizonData.PrimaryPlaceOfUseLastName}";
else
remoteDevice.Name = Core.Constants.Common.Undefined;
// set device Model
var verizonGroup = allVerizonGroups.Where(a => a.VerizonGroupName == remoteDevice.VerizonData.GroupName).FirstOrDefault();
if (!verizonGroup.DeviceModelId.HasValue)
VerizonGroupIsNotLinkedWithDeviceModelEvent?.Invoke(remoteDevice);
else
remoteDevice.DeviceModelId = verizonGroup.DeviceModelId;
// set device status
remoteDevice.Status = remoteDevice.VerizonData.State.ConvertToDeviceStatusFromVerizonStatus();
if (!string.IsNullOrWhiteSpace(remoteDevice.VerizonData.CarrierName))
{
var verizonCarrier = allVerizonCarriers.Where(a => a.VerizonCarrierName == remoteDevice.VerizonData.CarrierName).FirstOrDefault();
if (verizonCarrier.CarrierId.HasValue)
remoteDevice.CarrierId = verizonCarrier.CarrierId;
else
{
// notify that carrier is not found locally
LocalCarrierIsNotFoundForNewDeviceEvent?.Invoke(remoteDevice);
}
}
remoteDevice.SyncVerizon = true;
_context.Devices.Add(remoteDevice);
newDevices.Add(remoteDevice);
}
}
}
await _context.SaveChangesAsync();
why so? only one record has 1420531689, old was updated for new value (111111111) and it saved in the one transaction... How to do it correctly?

Entity Framework - how to save entity without saving related objects

In my Entity Framework, I have three related entities 'Client', 'ClientAddress' and 'LookupAddressType'. "LookupAddressType" is a master class specifying the type of available address type, like business address, residential address etc. ClientAddress depend on LookupAddresstype and Client. While saving a Client entity with relevant ClientAddress data, i'm getting following error.
"Violation of PRIMARY KEY constraint 'PK_LookupAddressType'. Cannot
insert duplicate key in object 'dbo.LookupAddressType'. The statement
has been terminated.
I do not need LookupAddressType to be inserted. Here I just need the relevant lookupAddressTypeId to be inserted in clientAddress entity.
The Saving code is like this:
Add(Client);
_objectContext.SaveChanges();
how can i do this?
The Load Code is below:
private void LoadClientDetails(EFEntities.Client _Client)
{
EFEntities.LookupClientStatu clientStatus;
var clientAddressList = new List<ClientAddress>();
if (_Client == null)
{
return;
}
//Assign data to client object
_Client.ClientName = rtxtName.Text;
_Client.Alias = rtxtAlias.Text;
_Client.ClientCode =Int32.Parse(rtxtClientCode.Text);
_Client.TaxPayerID = rtxtTaxPayerId.Text;
if (rcboStatus.SelectedIndex != 0)
{
clientStatus = new EFEntities.LookupClientStatu
{
ClientStatusID = (Guid) (rcboStatus.SelectedValue),
ClientStatusDescription = rcboStatus.Text
};
_Client.LookupClientStatu = clientStatus;
}
//_Client.Modified = EnvironmentClass.ModifiedUserInstance.Id;
_Client.EffectiveDate = rdtEffectiveDate.Value;
if (rdtExpDate.Value != rdtExpDate.MinDate)
{
_Client.ExpirationDate = rdtExpDate.Value;
}
else
{
_Client.ExpirationDate = null;
}
_Client.StartDate = DateTime.Now;
EFEntities.ClientAddress clientAddress = null;
// Iesi.Collections.Generic.ISet<ClientAddress> clientAddress = new HashedSet<ClientAddress>();
foreach (var cAddress in _clientController.client.ClientAddresses)
{
clientAddress = cAddress;
break;
}
if (clientAddress == null)
{
clientAddress = new EFEntities.ClientAddress();
}
clientAddress.Address1 = rtxtClientAdd1.Text;
clientAddress.Address2 = rtxtClientAdd2.Text;
clientAddress.Address3 = rtxtClientAdd3.Text;
// Address type details
if (rcboClientAddType.SelectedIndex != -1)
{
clientAddress.LookupAddressType = new EFEntities.LookupAddressType
{
AddressTypeID = (Guid) (rcboClientAddType.SelectedValue),
AddressTypeDescription = rcboClientAddType.Text
};
//clientAddress.AddressType.Id = Convert.ToByte(rcboClientAddType.SelectedValue);
}
clientAddress.City = rtxtClientCity.Text;
clientAddress.Client = _Client;
\
_Client.ClientAddresses.Add(clientAddress);
}
Well I did this to the following lines of code to make it work.
if (rcboClientAddType.SelectedIndex != -1)
{
clientAddress.LookupAddressType = new EFEntities.LookupAddressType
{
AddressTypeID = (Guid) (rcboClientAddType.SelectedValue),
AddressTypeDescription = rcboClientAddType.Text
};
//clientAddress.AddressType.Id = Convert.ToByte(rcboClientAddType.SelectedValue);
}
I changed the above code into this
if (rcboClientAddType.SelectedIndex != -1)
{
//clientAddress.LookupAddressType = new EFEntities.LookupAddressType
// {
// AddressTypeID = (Guid) (rcboClientAddType.SelectedValue),
// AddressTypeDescription = rcboClientAddType.Text
// };
clientAddress.AddressTypeID = (Guid)(rcboClientAddType.SelectedValue);
}

Entity Framework code first - update function failed

Inner exception message: A referential integrity constraint violation occurred: The property values that define the referential constraints are not consistent between principal and dependent objects in the relationship.
dynamic obj = "";
if (model.LoadResultCount!=0)
{
obj = new LoadManagementResultsCountUserSetting();
obj.ResultsCount = Convert.ToInt16(model.LoadResultCount);
obj.Id = Convert.ToInt16(model.LoadResultCountId);
//var loadManagementResultCount = ApplicationService.GetSettings<LoadManagementResultsCountUserSetting>(f => f.Id == model.LoadResultCountId).FirstOrDefault();
//ApplicationService.Remove(loadManagementResultCount);
SaveResultCountUserSettings(obj, model);
}
if (model.PlanningResultCount!=0)
{
obj = new PlanningManagementResultsCountUserSetting();
obj.ResultsCount = Convert.ToInt16(model.PlanningResultCount);
obj.Id = Convert.ToInt16(model.PlanningResultCountId);
//var planningManagementResultCount = ApplicationService.GetSettings<PlanningManagementResultsCountUserSetting>().Where(f => f.Id == model.PlanningResultCountId).FirstOrDefault();
//ApplicationService.Remove(planningManagementResultCount);
SaveResultCountUserSettings(obj, model);
}
private void SaveResultCountUserSettings(dynamic obj, ResultCountViewModel model)
{
obj.IsEnabled = true;
obj.IsPrimary = model.IsPrimary;
obj.StartDate = DateTime.UtcNow;
obj.ModifiedDate = DateTime.UtcNow;
obj.ModifiedBy = AuthenticatedUser;
ApplicationService.Save(obj);
}
public void Save(BaseLogixSetting setting)
{
if (setting != null)
{
if (setting.Id > 0)
SettingsRepository.Attach(setting);
else
SettingsRepository.Add(setting);
Commit();
}
}

Entity Framework overwrites data when 2 two people save data simultaneously

In a function I pass a list of related values and loop over them to save changes in the database. All works well until 2 or more people use the same page to update different entities .Then only that data gets saved for which the changes were made more recently.
public bool UpdatePermanentDifferenceBL(List<PermanentDifferenceProperties> permDiffDetails)
{
try
{
int permanentDifferenceID=0;
int taxEntityID = 0;
int mapid = 0;
//using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))
//{
Topaz.DAL.PermanentDifference permDiff;
for (int i = 0; i < permDiffDetails.Count; i++)
{
if ((bool)(HttpContext.Current.Session[GlobalConstant.currentDataSet]) == true && (int)(HttpContext.Current.Session[GlobalConstant.snapShotID]) == 0)
{
using (var ctx = new TopazDbContainer())
{
try
{
permanentDifferenceID = permDiffDetails[i].PermanentDifferenceID;
taxEntityID = permDiffDetails[i].TaxEntityID;
mapid = permDiffDetails[i].MapID;
permDiff = new Topaz.DAL.PermanentDifference();
permDiff = ctx.PermanentDifference.Where(p => p.PermanentDifferenceID == permanentDifferenceID && p.TaxEntityID == taxEntityID && p.MapID == mapid).SingleOrDefault();
permDiff.Business = permDiffDetails[i].Business;
permDiff.Interest = permDiffDetails[i].Interest;
permDiff.Corporate = permDiffDetails[i].Corporate;
permDiff.UnallocatedTax = permDiffDetails[i].UnallocatedTax;
permDiff.Total = permDiffDetails[i].Total;
permDiff.ModifiedBy = permDiffDetails[i].ModifiedBy;
permDiff.ModifiedDate = DateTime.Now;
ctx.SaveChanges();
}
catch (System.Data.OptimisticConcurrencyException ex)
{
permanentDifferenceID = permDiffDetails[i].PermanentDifferenceID;
taxEntityID = permDiffDetails[i].TaxEntityID;
mapid = permDiffDetails[i].MapID;
permDiff = new Topaz.DAL.PermanentDifference();
ctx.Refresh(System.Data.Objects.RefreshMode.StoreWins, permDiff);
permDiff = ctx.PermanentDifference.Where(p => p.PermanentDifferenceID == permanentDifferenceID && p.TaxEntityID == taxEntityID && p.MapID == mapid).SingleOrDefault();
permDiff.Business = permDiffDetails[i].Business;
permDiff.Interest = permDiffDetails[i].Interest;
permDiff.Corporate = permDiffDetails[i].Corporate;
permDiff.UnallocatedTax = permDiffDetails[i].UnallocatedTax;
permDiff.Total = permDiffDetails[i].Total;
permDiff.ModifiedBy = permDiffDetails[i].ModifiedBy;
permDiff.ModifiedDate = DateTime.Now;
ctx.SaveChanges();
}
}
}
//ctx.ContextOptions.UseLegacyPreserveChangesBehavior = true;
}
//}
//using (UnitOfWork uow = new UnitOfWork())
//{
// for (int i = 0; i < permDiffDetails.Count; i++)
// {
// if ((bool)(HttpContext.Current.Session[GlobalConstant.currentDataSet]) == true && (int)(HttpContext.Current.Session[GlobalConstant.snapShotID]) == 0)
// {
// Repository.PermanentDifferenceRepository pDiffRepo = new Repository.PermanentDifferenceRepository(uow);
// Topaz.DAL.PermanentDifference permDiff = pDiffRepo.GetByEntityId(permDiffDetails[i].PermanentDifferenceID, permDiffDetails[i].TaxEntityID, permDiffDetails[i].MapID);
// permDiff.Business = permDiffDetails[i].Business;
// permDiff.Interest = permDiffDetails[i].Interest;
// permDiff.Corporate = permDiffDetails[i].Corporate;
// permDiff.UnallocatedTax = permDiffDetails[i].UnallocatedTax;
// permDiff.Total = permDiffDetails[i].Total;
// permDiff.ModifiedBy = permDiffDetails[i].ModifiedBy;
// permDiff.ModifiedDate = DateTime.Now;
// pDiffRepo.ApplyChanges(permDiff);
// }
// else
// {
// int snapshotID = (int)(HttpContext.Current.Session[GlobalConstant.snapShotID]);
// SnapShotPermanentDifferenceRepository pDiffRepo = new SnapShotPermanentDifferenceRepository(uow);
// SnapShotPermanentDifference permDiff = pDiffRepo.GetByEntityId(permDiffDetails[i].PermanentDifferenceID, permDiffDetails[i].TaxEntityID, permDiffDetails[i].MapID,snapshotID);
// permDiff.SnapshotID = snapshotID;
// permDiff.Business = permDiffDetails[i].Business;
// permDiff.Interest = permDiffDetails[i].Interest;
// permDiff.Corporate = permDiffDetails[i].Corporate;
// permDiff.UnallocatedTax = permDiffDetails[i].UnallocatedTax;
// permDiff.Total = permDiffDetails[i].Total;
// permDiff.ModifiedBy = permDiffDetails[i].ModifiedBy;
// permDiff.ModifiedDate = DateTime.Now;
// pDiffRepo.ApplyChanges(permDiff);
// }
// }
// uow.SaveChanges();
return true;
}
catch (Exception ex)
{
TopazErrorLogs.AddTopazErrorLogBL(ex, 1, 1);
throw new TopazCustomException(GlobalConstant.errorMessage);
}
}
Any urgent assistance is much appreciated.
The common way to solve this is adding additional column to every table where you want to handle concurrency. This column will have ROWVERSION or TIMESTAMP data type. Once you map tables in EDMX you will get a new computed property of type byte[] and set its Concurrency mode to fixed. This setting will force EF to add additional WHERE condition to every UPDATE or DELETE statement validating that row version is the same as it was when the record was loaded from the database. If the row version is not the same (another thread updated the record) the record from modification is not found and you will get exception.
Database will change the value every time you update the record automatically. You just need to ensure that your entity uses the value which was retrieved when the entity was loaded from the database.
Apologies all the viewstate and to some extent session was the culprit and not EntityFramework.

Entity Framework 4.0 Error The object could not be added or attached EntityReference has EntityKey value that does not match EntityKey

Hi everybody im starting to work with Entity Framework 4.0 and ASP.NET 4.0 i'm trying to make a master detail web page and i'm having problems when i try to add new items to a previously recorded items below is the i made for this:
private void guardarOrdenMedicamento()
{
InventarioSIAIplusEntities SIAplusContext = (InventarioSIAIplusEntities)(Session["context"]);
InvOrden orden;
string resultMessage;
if (DetalleMedicamentosOrden.Count == 0)
{
MessageBox1.ShowError("Debe especificar al menos un medicamento para la orden.");
return;
}
if (txtIDorden.Text.Trim() == "")
{
orden = new InvOrden();
orden.IDcentro = Convert.ToInt32(ddlCentros.SelectedValue);
orden.estado = ddlEstadoOrden.SelectedValue;
orden.fecha = Convert.ToDateTime(txtFechaCreacion.Text);
orden.comentario = txtComentarioOrden.Text;
orden.usuarioCrea = "Jeanc";
SIAplusContext.AddToInvOrdenes(orden);
resultMessage = "La orden fue registrada satisfactoriamente";
}
else
{
int idorden = Convert.ToInt32(txtIDorden.Text.Trim());
orden = SIAplusContext.InvOrdenes.Where(c => c.IDorden == idorden).First();
orden.estado = ddlEstadoOrden.SelectedValue;
orden.fecha = Convert.ToDateTime(txtFechaCreacion.Text);
orden.comentario = txtComentarioOrden.Text;
orden.usuarioCrea = "Jeanc";
resultMessage = "La orden fue actualizada satisfactoriamente";
foreach (var item in DetalleMedicamentosOrden)
{
if (item.IDorden == 0)
{
// item.IDorden = idorden;
// item.InvOrdenReference.EntityKey = orden.EntityKey;
//neww System.Data.EntityKey("InventarioSIAIplusEntities.InvOrdenes", "IDorden", orden.IDorden);
// SIAplusContext.AddToInvOrdenDets(item);
item.InvOrden = orden;
//
// SIAplusContext.AddToInvOrdenDets(item);
//orden.InvOrdenDets.Add(item);
}
else
{
InvOrdenDet det = SIAplusContext.InvOrdenDets.Where(c => c.IDorden == item.IDorden && c.IDmedicamento == item.IDmedicamento).First();
det.cantidadApr = item.cantidadApr;
det.cantidadSol = item.cantidadSol;
det.comentario = item.comentario;
}
}
}
SIAplusContext.SaveChanges();
}
The Error is :The object could not be added or attached because its EntityReference has an EntityKey property value that does not match the EntityKey for this object.
Thanks For any help with this.
I think that the problem is here:
item.InvOrden = orden;
You either have to use AddObject or update the values of an existing object.