Entity Framework the delete statement conflicted with the reference constraint - entity-framework

I have two tables Employee (n) and Store (1), which have n:1 relationship.
Employee has foreign key idStore which is primary key from Store.
Here is how I try to delete a row from Employee:
public void deleteEmployee(int idEmployee)
{
MyEntities pe = new MyEntities();
try
{
var firstQuery = from e in pe.Employees
where e.idEmployee == idEmployee
select e;
string findIdStore = firstQuery.First().StoreReference.EntityKey.EntityKeyValues[0].Value.ToString();
int idStore = Int32.Parse(findIdStore);
Store r = pe.Stores.First(c => c.idStore == idStore);
r.Employees.Remove(firstQuery.First());
pe.DeleteObject(firstQuery.First());
pe.SaveChanges();
}
catch (Exception ex)
{
return;
}
}
And still, I get error that the delete statement conflicted with the reference constraint.
The complete error is here:
The DELETE statement conflicted with the REFERENCE constraint
"FK_Bill_Employee". The conflict occurred in database
"myDatabase", table "dbo.Bill", column 'idEmployeeMember'.
The statement has been terminated.

Can't you just find and delete the employee??
public void deleteEmployee(int idEmployee)
{
using(MyEntities pe = new MyEntities())
{
var emmployeeToDelete = pe.Employees.FirstOrDefault(e => e.idEmployee == idEmployee);
if(employeeToDelete != null)
{
pe.DeleteObject(employeeToDelete);
pe.SaveChanges();
}
}
}
I don't think you need to do anything more than this, really.....
Next time when you load this particular store the employee belonged to, that employee will no longer be in the store's collection of employees - without doing any messy manual deletes or anything....

Related

Entity Framework is failing to delete a record from an associated table throwing an error

I have a simple association table whose PK isn't referenced anywhere but when I am trying to delete a record from it in the following way, I get an error. I am using EF code-first. Any help would be very very helpful. Thanks in advance.
List<ViolationTypeNOV> novRels = UnitOfWork.Context.ViolationTypeNOVs.Where(x => x.NOVId == nov.NOVId).Include("ViolationType").Include("NOV").ToList();
foreach (ViolationTypeNOV o in novRels)
{
UnitOfWork.Context.ViolationTypeNOVs.Remove(o);
}
UnitOfWork.Context.SaveChanges();
Here is the error message I am getting. If the table's PK isn't referenced in any way, why is it failing with this error? Just not able to understand:
The operation failed: The relationship could not be changed because one or more of the foreign-key properties is non-nullable. When a change is made to a relationship, the related foreign-key property is set to a null value. If the foreign-key does not support null values, a new relationship must be defined, the foreign-key property must be assigned another non-null value, or the unrelated object must be deleted.
The same thing if I am running through SSMS same thing is working though:
DELETE ViolationTypeNOVs
WHERE ViolationTypeNOVId = 2
Why?
But again if I am running the same query through context as below, I get the same error at the calling SaveChanges:
foreach (ViolationTypeNOV o in novRels)
{
string str = string.Format("Delete ViolationTypeNOVs where ViolationTypeNOVId = {0}", new object[] { o.ViolationTypeNOVId });
UnitOfWork.Context.Database.ExecuteSqlCommand(str);
}
UnitOfWork.Context.SaveChanges();
It seems like some of the objects within the context aren't nulling or getting deleted, is there anyway to clear them all in one go? Because these ids/objects are used in multiple places in the code - please let me know how to clear them all - thanks a lot.
Any help please?
Fixed it - the problem is we need to clear up all the objects and its links that the parent object is using then only we can save the changes thanks here is my solution
public bool Delete(NOV nov, bool performCommit = true)
{
System.Data.Entity.DbContextTransaction dbOperation = null;
if (performCommit)
dbOperation = UnitOfWork.BeginTransaction();
try
{
//-- Remove the Items - "foreach" approach was a problem
// http://weblogs.asp.net/ricardoperes/entity-framework-pitfalls-deleting-orphans
//------------------------------------------------------
// Remove the Violations that are in this NOV
//------------------------------------------------------
List<Violation> violationIdlist = new List<Violation>();
foreach (var v in nov.ViolationNOVs)
{
var a = UnitOfWork.ViolationRepository.GetAll().Where(z => z.ViolationId == v.ViolationId).FirstOrDefault();
violationIdlist.Add(a);
}
foreach (var v in violationIdlist)
{
var a = nov.ViolationNOVs.Where(x => x.NOVId == nov.NOVId && x.ViolationId == v.ViolationId)?.FirstOrDefault();
nov.ViolationNOVs.Remove(a);
}
nov.IssuedBy.Clear();
//deleting all OneToMany references to NOV
List<ViolationTypeNOV> novRels = UnitOfWork.Context.ViolationTypeNOVs.Where(x => x.NOVId == nov.NOVId).Include("ViolationType").Include("NOV").ToList();
nov?.ViolationTypeNOVs?.Clear();
//foreach (ViolationTypeNOV o in novRels)
//{
// UnitOfWork.Context.ViolationTypeNOVs.Remove(o);
// o?.ViolationType?.ViolationTypeNOVs?.Remove(o);
// nov?.ViolationTypeNOVs?.Remove(o);
//}
UnitOfWork.Context.ViolationTypeNOVs.RemoveRange(novRels);
List<ViolationNOV> violationNOVs = UnitOfWork.Context.ViolationNOVs.Where(x => x.NOVId == nov.NOVId).Include("Violation").Include("NOV").ToList();
nov?.ViolationNOVs?.Clear();
UnitOfWork.Context.ViolationNOVs.RemoveRange(violationNOVs);
List<CaseNOV> caseNOVs = UnitOfWork.Context.CaseNOVs.Where(x => x.NOVId == nov.NOVId).Include("Case").Include("NOV").ToList();
nov?.CaseNOVs?.Clear();
UnitOfWork.Context.CaseNOVs.RemoveRange(caseNOVs);
UnitOfWork.Context.SaveChanges();
if (dbOperation != null)
dbOperation.Commit();
LogHandler.LogInfo(2521, "Deleted NOV " + nov.NOVNumber);
return true;
}
catch (Exception ex)
{
LogHandler.LogError(2523, "Commit Fail in NOV Delete", ex);
if (dbOperation != null)
dbOperation.Rollback();
throw ex;
}
}
This statement has fixed the problem: UnitOfWork.Context.ViolationTypeNOVs.RemoveRange(novRels); thanks a lot for everybody who tried to help me

Salesforce Lead Trigger CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY

I want to clone the Profile__c record. The lead has a profile__c associated with it. When conversion happens, the Profile_c on the lead is copied to the account created. What I need to do is a deep clone of the Profile__c on the new account created after the conversion. I am able to copy the profile_c over but cloning throws this error:
Error: System.DmlException: Update failed. First exception on row 0 with id 00QJ0000007dDmHMAU; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, profile: execution of AfterUpdate caused by: System.DmlException: Insert failed. First exception on row 0; first error: CANNOT_UPDATE_CONVERTED_LEAD, cannot reference converted lead: [] Trigger.profile:, column 1: [] (System Code)
trigger profile on Lead (after update) {
Map<Id, Lead> cl = new Map<Id,Lead>();
Lead parent;
List<Contact> clist = new List<Contact>();
Set<Id> convertedids = new Set<Id>();
//list of converted leads
for (Lead t:Trigger.new){
Lead ol = Trigger.oldMap.get(t.ID);
if(t.IsConverted == true && ol.isConverted == false)
{
cl.put(t.Id, t);
convertedids.add(t.ConvertedContactId);
}
}
Set<Id> leadIds = cl.keySet();
List<Profile__c> mp = [select Id, lock__c, RecordTypeId, reason__c, End_Date__c,startus__c , Opportunity__c, Account__c, Lead__c from Profile__c where Lead__c in :leadIds];
List<ID>AccountIDs = new List<ID>();
List<Profile__c>clonedList = new list<Profile__c>();
for (Profile__c mpi:mp){
parent = cl.get(mpi.Lead__c );
mpi.opportunity__c = parent.ConvertedOpportunityId;
mpi.account__c = parent.ConvertedAccountId;
AccountIDs.add(parent.ConvertedAccountId);
Profile__c profile = mpi.clone(false,true,false,false);
clonedList.add(profile);
mpi.lock__c= true;
mpi.reason__c= 'Converted';
}
update mp;
insert clonelist
}
You are doing insert operation(insert clonelist) in which you are accessing Converted lead Id value in a field. You can't use converted LeadId field in DML operations.
Below is the Sample code that will work-
trigger ConvertedLead_Trigger on Lead (after update) {
Map<Id, Lead> cl = new Map<Id,Lead>();
Lead parent;
List<Contact> clist = new List<Contact>();
Set<Id> convertedids = new Set<Id>();
//list of converted leads
for (Lead t:Trigger.new){
Lead ol = Trigger.oldMap.get(t.ID);
if(t.IsConverted == true && ol.isConverted == false)
{
cl.put(t.Id, t);
convertedids.add(t.ConvertedContactId);
}
}
Set<Id> leadIds = cl.keySet();
List<ConvertLeadTest__c> mp =[Select Id,Name,Lead__c, Account__c,Opportunity__c from ConvertLeadTest__c where Lead__c in :leadIds];
List<ConvertLeadTest__c> mp1=new List<ConvertLeadTest__c>();
List<ConvertLeadTest__c> mp2=new List<ConvertLeadTest__c>();
for(ConvertLeadTest__c cc:mp)
{
if(cl.containsKey(cc.Lead__c))
{
cc.Account__c=cl.get(cc.Lead__c).ConvertedAccountId;
cc.Opportunity__c=cl.get(cc.Lead__c).ConvertedOpportunityId;
mp1.add(cc);
mp2.add(new ConvertLeadTest__c(Account__c=cl.get(cc.Lead__c).ConvertedAccountId,Opportunity__c=cl.get(cc.Lead__c).ConvertedOpportunityId));
}
}
update mp;
insert mp2;
}
But if you write
ConvertLeadTest__c(Lead__c=cc.Lead__c,Account__c=cl.get(cc.Lead__c).ConvertedAccountId,Opportunity__c=cl.get(cc.Lead__c).ConvertedOpportunityId));
then it will throw error.
Hope this will help you.
Thanks :)
We are not able to perform any operation on the Lead once the lead is converted.
Anything you do to try o update the converted lead will give you error.
What eventually did it for me was after the conversion, I grabbed the convertedAccountIds. Since I was already copying Profile__c to the account after conversion, I just cloned the profile there and had to set the lead on that profile to null since it can't be updated

Error when updating many to many relation in EF5

I have an ASP.NET WebForms project with N-Layers using Entity Framework 5.
I have two entities: Cliente and Banda.
One Cliente may have many Banda's, and one Banda may have many Cliente's
In the bussines layer I have this code:
public void Update(Cliente cliente)
{
using (MegaStudioEntities contexto = new MegaStudioEntities())
{
if (contexto.Entry(cliente).State == EntityState.Detached)
contexto.Entry(cliente).State = EntityState.Modified;
//Delete existing relations
var qBandas = from qb in contexto.Bandas.Where(b => b.Clientes.Any(c => c.IdCliente == cliente.IdCliente))
select qb;
foreach (Banda b in qBandas.ToList())
((IObjectContextAdapter)contexto).ObjectContext.ObjectStateManager.ChangeRelationshipState(cliente, b, c => c.Bandas, EntityState.Deleted);
contexto.SaveChanges();
//Adding new relations
foreach (Banda banda in cliente.Bandas)
{
contexto.Bandas.Attach(banda);
((IObjectContextAdapter)contexto).ObjectContext.ObjectStateManager.ChangeRelationshipState(cliente, banda, c => c.Bandas, EntityState.Added);
}
cliente.TipoCliente = contexto.TipoClientes.Find(cliente.IdTipoCliente);
cliente.FechaModificacion = System.DateTime.Now;
Encriptar(cliente);
contexto.SaveChanges();
}
}
The first time I call Update method, run sucessfully, but the second time I get this error:
"An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key."
What I forget to close?
This is the correct way to update many to many relations in EF5?
Thanks in advance!!!
Martin
UPDATE 1:
Finally my code is like that:
public void Update(Cliente cliente)
{
using (MegaStudioEntities contexto = new MegaStudioEntities())
{
Cliente savedClient = contexto.Clientes.Find(cliente.IdCliente);
foreach (var banda in savedClient.Bandas.ToList())
{
savedClient.Bandas.Remove(contexto.Bandas.Find(banda.IdBanda));
}
foreach (var banda in cliente.Bandas)
{
savedClient.Bandas.Add(contexto.Bandas.Find(banda.IdBanda));
}
contexto.Entry(savedClient).CurrentValues.SetValues(cliente);
contexto.SaveChanges();
}
}
Thanks Gert Arnold!!!
You don't really have to attach any object to the context. So you can prevent this exception by not doing that.
public void Update(Cliente cliente)
{
using (MegaStudioEntities contexto = new MegaStudioEntities())
{
Cliente savedClient = contexto.TipoClientes.Find(cliente.IdCliente);
foreach (var banda in savedClient.Bandas.ToList())
{
savedClient.Bandas.Remove(banda);
}
foreach (var banda in cliente.Bandas)
{
savedClient.Bandas.Add(banda);
}
savedClient.IdTipoCliente = cliente.IdTipoCliente;
savedClient.FechaModificacion = System.DateTime.Now;
Encriptar(cliente);
contexto.SaveChanges();
}
}
I'm not sure if this break code in Encriptar(cliente); because (obviously) I don't know what happens there.
As you see, you add and remove associations in a m:m relationship by adding/removing objects. You hardly ever (probably never) need to manipulate relationship state explicitly. If you feel a need to do that it most likely indicates that you overlook an easier way to achieve what you want.

entity framework update

i know how to do updates, inserts and deletes with the entityframework but in this case i don't know what to do.
In this case i have 3 tables: the table A the table B and the table AB which has 2 columns, one is the foreing key of the table A and one is the foreing key of the table B.
The entity framework shows only the tables A and B so how i can update only the content of the table AB?
I've tried to use the references in entity A and entity B but it gives me an exception saying that the entityset AB doesn't have the insert function and the delete function.
You try to make a
Public Virtual List<int> Ids
in your "A" and "B" Class to recover all the associations
For an insert, you would create a record for Table A, then add the Table B records to the item created that inserts into A. EF will handle the rest.
var tableA = new TableAtype { Description = "blah", etc.};
tableA.TableBtype.Add(new TableBtype { Property1 = "foo", Property2 = "bar"};
yourContext.AddToTableAtype(tableA);
yourContext.SaveChanges();
i'll be more specific using the code of my project as asked by TheGeekYouNeed
public void ModificaAbilitazioni(int IdGruppoAnagrafica, List<DefAbilitazioni> AbilitazioniList)
{
GruppiAnag gruppo = (from g in entities.GruppiAnags
where g.IdGruppoAnag == IdGruppoAnagrafica
select g).First();
List<DefAbilitazioni> tutteAbilitazioni = GetTutteAbilitazioni();
for (int i = 0; i < AbilitazioniList.Count; i++)
{
if (tutteAbilitazioni[i].GruppiAnags.Contains(gruppo))
{
tutteAbilitazioni[i].GruppiAnags.Remove(gruppo);
}
}
foreach (DefAbilitazioni abilitazione in AbilitazioniList)
{
for (int i = 0; i < tutteAbilitazioni.Count; i++)
{
if (tutteAbilitazioni[i].IdAbilitazione == abilitazione.IdAbilitazione)
{
tutteAbilitazioni[i].GruppiAnags.Add(gruppo);
}
}
}
entities.SaveChanges();
}
ok...here it is
this method should change the privilegies accounts.
First i recover the account using his id, than i recover all the privilegies and if in their reference they have the account recovered, then i remove it from the reference.
This way the account doesn't have any privilegies. Now in the privilegies that i've passed calling the method and in theri reference i put the account. (just a wipe and refill i'm just trying for now...)
i've also di the opposite, wiping the privilegies references in the account and refill them, but in both way won't work, in the first case it says that the third entity (AB) doesn't have the insert function
i've resolved the thing, the problem was that i was working with objects not attached to the db, i've tried with the attach like this
foreach (DefAbilitazioni abilitazione in abilitazioni)
{
entities.Attach(abilitazione);
gruppo.DefAbilitazionis.Add(abilitazione);
}
but it doesn't work it says that the entitykey is null, maybe if somebody gives me an example of using the attach i'll try to change my code that now is like this
public void ModificaAbilitazioni(int IdGruppoAnagrafica, List<DefAbilitazioni> AbilitazioniList)
{
GruppiAnag gruppo = (from g in entities.GruppiAnags
where g.IdGruppoAnag == IdGruppoAnagrafica
select g).First();
IEnumerable<int> idAbilitazioni = from id in AbilitazioniList
select id.IdAbilitazione;
List<DefAbilitazioni> abilitazioni = (from abilitazione in entities.DefAbilitazionis
where idAbilitazioni.Contains(abilitazione.IdAbilitazione)
select abilitazione).ToList();
gruppo.DefAbilitazionis.Clear();
foreach (DefAbilitazioni abilitazione in abilitazioni)
{
gruppo.DefAbilitazionis.Add(abilitazione);
}
entities.SaveChanges();
}

updating table in entity framework 4 /mvc 3!

could you help with this? I bet this isn't any tough one..but am new to EF and facing a weekend deadline. I want to update a table with values.. but the primary key is identity column. So my task is like this.. if it exists, update.. if it doesn't add to the
table.. this is my code..and am stuck in this else part..!
Table structure is like this
Primary Key table - System: SystemId, SystemName
Foreign Key table - SystemConfiguration: SystemConfigurationId, SystemId, SystemRAM, SystemHard-Disk
public void SaveSystemConfigurations(SystemConfiguration systemConfig)
{
var config = (from s in Context.SystemConfiguration
where s.SystemId == systemConfig.SystemId
select s).FirstOrDefault();
if (config == null)
{
Context.SystemConfigurations.AddObject(systemConfig);
Context.SaveChanges();
}
else
{
// EntityKey systemConfigKey= new EntityKey("systemConfig", "systemConfigId", config.SystemConfigurationId);
Context.SystemConfigurations.Attach(systemConfig);
Context.SaveChanges();
}
}
Try this:
public void SaveSystemConfigurations(SystemConfiguration systemConfig)
{
var config = (from s in Context.SystemConfiguration
where s.SystemId == systemConfig.SystemId
select s).FirstOrDefault();
if (config == null)
{
Context.SystemConfigurations.AddObject(systemConfig);
}
else
{
config.Attribute = value; // Do your update here
}
Context.SaveChanges();
}
Edit. It should be config not systemConfig.
The ApplyCurrentValues method will apply scalar attributes to an entity that matches the same key. My assumption is that you are modifying a real entity (an object that has a valid entity key).
This would work:
var eSet = config.EntityKey.EntitySetName;
Context.ApplyCurrentValues(eSet, systemConfig);
Context.SaveChanges();
public void SaveSystemConfigurations(SystemConfiguration systemConfig)
{
var context = new EntitiesModel();
//here is the name of the partial class created on the Context area of the edmx designer.cs
var config = (from s in context.SystemConfiguration
where s.SystemId == systemConfig.SystemId
select s).FirstOrDefault();
context.ApplyCurrentValues(config.EntityKey.EntitySetName, systemConfig);
// systemConfig comes from the view with values set by the user
// you dont have to manually need to map one value at the time
context.SaveChanges();
}