I am new to Entity Framework so I need help with deleting an object from an entity.
I have 2 tables which are in many to many relationship and an association table connecting them in the database. In the model there are only two tables and the association one is presented by navigation properties as this is how the EF works. Now I need to delete an object from the first table by context.EntityName.DeleteObject(object) but when I try to do it the code fails with error "The DELETE statement conflicted with the REFERENCE constraint FK..", which is a foreign key from the association table to the entity, which object I try to delete. I wonder how to fix this. Could you please help me?
Here is how the tables look like:
Teachers
Teacher_ID
FirstName
LastName
TimetableDetail
TimetableDetail_ID
EducationalDiscipline_ID
Weekday
StartTime
Duration
and the associaion table:
TimetableDetailTeachers
Teacher_ID
TimetableDetail_ID
And here is how I try to delete it:
TimetablesEntities context = new TimetablesEntities();
TimetableDetail detail = context.TimetableDetails.SingleOrDefault(td => td.TimetableDetail_ID == timetableDetailId);
context.TimetableDetails.DeleteObject(detail);
context.SaveChanges();
Thanks in advance!
You just need to clear the association table by clearing the Teachers list for a particular TimetableDetail. Using your code...
TimetablesEntities context = new TimetablesEntities();
TimetableDetail detail = context.TimetableDetails.SingleOrDefault(td => td.TimetableDetail_ID == timetableDetailId);
detail.Teachers.Clear();
context.TimetableDetails.DeleteObject(detail);
context.SaveChanges();
The key line being detail.Teachers.Clear()
Yeah, this is a tricky one.
What you need to do is clear the entities out of the EF's underlying local storage. The example shows what to do when you clear all details for a specific teacher (or even only some details) and then save that teacher's entity. With that in mind, here is some example repository code:
public void EditTeacher(Teacher teacher)
{
if (teacher == null)
{
throw new ArgumentNullException("teacher");
}
YourDbContext.Entry(teacher).State = EntityState.Modified;
// Remove all timetable details that have an orphaned relationship.
// (E.g., orphaning occurs when 'teacher.TimetableDetails.Clear()'
// is called or when you delete one particular TimetableDetail
// entity for a teacher)
YourDbContext.TimetableDetails
.Local
.Where(td => td.Teacher == null)
.ToList()
.ForEach(td => YourDbContext.TimetableDetails.Remove(td));
YourDbContext.SaveChanges();
}
I hope this helps.
For further reading, take a look at: Deleting orphans with Entity Framework.
Edit:
The example code above assumes that elsewhere in your code you have defined and created YourDbContext as a member variable within your repository class. I just wanted to point that out in case it wasn't clear.
You could do:
add row before remove detail:
context.Teachers.RemoveRange(detail.Teachers);
The key line being that...
Related
I am trying to update a parent entity, GuildMemberTeam, with child entities, GuildMember, Team and GuildMemberChallenge which also has a child entities, GuildMember and Challenge but am getting the following inner exception:
Inner Exception 1: SqlException: Violation of PRIMARY KEY constraint
'PK_Challenge'. Cannot insert duplicate key in object 'dbo.Challenge'.
The duplicate key value is (15ae8798-8567-457b-812a-5820cf7843e5). The
statement has been terminated.
The only new entity is the GuildMemberTeam as all the others already exist, but these are checked and recreated as follows:
public void AddChallenge(Challenge challenge)
{
if (challenge != null)
{
var id = challenge.Id == default(Guid) ? Guid.NewGuid() : challenge.Id;
Challenge = new Challenge(id, challenge.Name, challenge.Phase, challenge.Type, challenge.Star, challenge.Gear, challenge.Level, challenge.Reward);
}
}
This works for all the other entities apart from Challenge where i get the error. Can anyone please help me understand what i am doing wrong.
It doesn't change the fact that the problem is that you are trying to insert the same row twice (same Guid=Id) into the dbo.Challenge table.
This might be due to a debugging issue or something. You can either delete the row from the table with a
DELETE FROM [Challenge] WHERE Id = '15ae8798-8567-457b-812a-5820cf7843e5' and try running the app again.
If this doesn't solve your problem your entity management is faulty and you have to revise the ID handling. Implement ID checking before you try to save your context or something like that.
The other issue might be that your classes are not defined properly and EF doesn't recognize the relations. The relationships you are talking about are not parent-child, they are either one-to-many, many-to-many, many-to-one or none. DB RELATIONS
Each of your POCO-s should contain and instance of the other class, thus you define a relationship. E.g. if your GuildMemberChallenge contains an IEnumerable and a property with type of challenge.
If none of the above are a solution I need some more code (your classes, the repository) to figure it out.
Update:
When you are adding a new GuildMemberChallenge, which I assume you are trying to do now. You should set it's Challenge property to an existing entity if it exists, if it doesn't you can create one, but at the moment you are trying to create a Challenge that already exists in the database.
You are creating new Challenge but pass id of existing Challenge if it is set.
var id = challenge.Id == default(Guid) ? Guid.NewGuid() : challenge.Id;
I think you, that if you create new entity you should always create new Id
var id = Guid.NewGuid();
I have a Model-First entity model which contains a Customer table linked to a view that fetches customer details from a separate database. The relationship is One to Many between the Customer table and the View and I have a navigation property on both the Customer entity and the View entity.
When I try to perform a delete using context.Customers.DeleteObject(cust) and call context.SaveChanges() I get an error:
Unable to update the EntitySet 'ViewEntity' because it has a DefiningQuery and no [DeleteFunction] element exists element to support the current operation.
I have tried setting On Delete Cascade and None and both generate the same error.
EDIT: There's not much code to show, but here you go:
Customer selectedCust = (Customer)dgvCustomers.SelectedRows[0].DataBoundItem;
if (selectedCust != null)
{
if (MessageBox.Show(String.Format("Are you sure you want to delete Customer {0}?", selectedCust.CustomerID.ToString()),
"Customer Delete Confirmation", MessageBoxButtons.YesNo) == DialogResult.Yes)
{
// TODO - Fix this
this.ReportSchedDBContext.Customers.DeleteObject(selectedCust);
this.ReportSchedDBContext.SaveChanges();
}
}
Many related posts in SO agree with #Overmachine... you are probably missing a primary key on your entity/table.
See..
because it has a DefiningQuery and no <InsertFunction> element exists in the <ModificationFunctionMapping> element
and
Unable to update the EntitySet - because it has a DefiningQuery and no <UpdateFunction> element exist
EDIT
Just saw your comment regarding your Customer table having a primary key but your view not. Not sure whats going on without more of your code, but ultimately all you need is a Customer object with the primary key(s) set on it, then you can use the following code to delete a detached entity object.
this.ReportSchedDBContext.Entry(selectedCust).State = EntityState.Deleted;
this.ReportSchedDBContext.SaveChanges();
If you are casting from another type and that is causing problems, you could also do:
var cust = new Customer { CustomerID = selectedCust.CustomerID };
this.ReportSchedDBContext.Entry(cust).State = EntityState.Deleted;
this.ReportSchedDBContext.SaveChanges();
I was able to work around this issue by creating a dummy Stored Procedure that does nothing ("SELECT 'Done'") and using the SP Function Mapping in my two Views to set the Delete function to this Stored Procedure. Quite a hack but it worked.
I'm not sure why a Delete Function is required for a View or if I'm doing something else wrong which caused the issue, but the above worked for me.
I think you should use of all foreign keys in View. when you use all foreign keys and primary keys in view you can update and delete object as cascade.
After adding table Person to database and updating the model from database table, entity Person exists, but is not present in
Entity ctx = new Entity();
ctx.Persons // doesn't exists
How can I fix that? Thanks
Update: table had 2 foreign keys, after I delete one of them - Persons appeared in ctx. Is there any constraint to have 2 foreign keys?
Update №2: EF named table Person as People. WTF???
Ef pluralization of tables for table names is performed unless you specify a table name via annotation or using fluent API modelBuilder.Entity<TPoco>().ToTable("TName", "schema");
Would need to see exception and Custom DBContext class to comment further.
sorry, but you don't provide a lot of context for your question, check some online tutorial like http://blogs.msdn.com/b/webdev/archive/2013/11/01/tutorial-series-updated-for-entity-framework-6-code-first-with-mvc-5.aspx
I'm trying to update an existing entity.
I have the following code:
public MamConfiguration_V1 Save(MamConfiguration_V1 item)
{
mMaMDBEntities.MamConfiguration_V1.Attach(item);
mMaMDBEntities.ObjectStateManager.ChangeObjectState(item, System.Data.EntityState.Modified);
mMaMDBEntities.SaveChanges();
return item;
}
But the Attach methods throws an exception:
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.
How can I fix this?
Seems like you have some relationship with foreign key field and a navigation property in the item, and those fields have conflicting values. This occurs when you load an entity and its related entities, change the relationship at one end, mark only that end as Modified and attempt to save. Make sure you modify relationship at both ends and mark all the affected entities as Modified before calling SaveChanges.
I encountered this exception under a different set of circumstances, and am posting here since this question comes up when the error message is searched.
The exception was thrown when calling IObjectContextAdapter.ObjectContext.AttachTo(entitySetName, entity) with a partially-loaded entity. The foreign keys on the entity were defined, but the navigational properties were not loaded. (That is, O.ItemID had a value, but O.Item was null). The specific circumstances did not allow O.Item to be loaded.
The problem turned out to be that the Object State Manager had loaded the object in a separate method and was already tracking the object defined with the same keys. Since the separate method did not need to track the object state, the issue was resolved by calling IQueryable.AsNoTracking() within that method.
What is the definition of the item object? It seems that in some of its collections that set the realionship with other entities exist some type of conflict. You could try to clear all the collections to see if the problem persists, but in this case you lost the foreign key assignment. But perhaps it could help you to locate the problem.
This could be a tip. When I try to attach an existing entity to the context, I use to do the following:
mMaMDBEntities.Entry<MamConfiguration>(item).State = System.Data.EntityState.Modified;
You can add the using of System.Data to avoid the needed to write it all the time.
This attach the entity in the state that you want, modified in this case and track the changes. This is one line instead of two.
The issue for me was that entity framework had loaded my object in multiple places, so when I updated a foreign key, there were now two references to the same object, one with a foreign key pointing to record a and one with a foreign key pointing to record b, which caused an error since my relationship is one to one. To resolve it, I used context.Entry(Object).State = EntityState.Detached, reloaded the object, made the foreign key change and then saved my changes
Lets say you have the following schema:
If you want to edit the CurrentLocationId in Person, you also need to edit the CurrentLocation object embedded in the Person object. EF will automatically populate the CurrentLocation object because CurrentLocationId has a foreign key in the CurrentLocation's table. When you edit the CurrentLocationId without updating the CurrentLocation object as well, they become out of sync. This is what causes the exception in this case.
So let's say you needed to update the Person object's CurrentLocationId. We'll assume you pre-fetched the Person data and the Location data.
public class DbData
{
List<Person> PersonList;
List<Location> LocationList;
public DbData()
{
using (var context = new MyContext())
{
PersonList = context.Persons.ToList();
LocationList = context.Locations.ToList();
}
}
public void UpdatePersonLocation(Person person, int newLocationId)
{
using (var context = new MyContext())
{
var location = LocationList.Where(l=>l.id==newLocationId).Single();
//you need to update both the id and the location for this to not throw the exception
person.CurrentLocationId == newLocationId;
person.CurrentLocation == location;
context.Entry(person).State = System.Data.Entity.EntityState.Modified;
context.SaveChanges();
}
}
//or if you're giving it the location object...
public void UpdatePersonLocation(Person person, Location location)
{
using (var context = new MyContext())
{
//you need to update both the id and the location for this to not throw the exception
person.CurrentLocationId == location.id;
person.CurrentLocation == location;
context.Entry(person).State = System.Data.Entity.EntityState.Modified;
context.SaveChanges();
}
}
}
This might be an old post but the following worked for me
set the SaveOptions option to SaveOptions.DetectChangesBeforeSave
I'm trying to delete a record from my table using EF, and nothing is happening. The code executes with no errors, but the record just sticks around in the DB. I have nearly identical code elsewhere that's working.
using (var DB = new PTNWebConfigurationModel.PTNWebConfigurationEntities())
{
var account = DB.Accounts.Where(a => a.LoginID == loginID).FirstOrDefault();
//Load existing session for the Account, otherwise create a new one.
if (!LoadExistingSession(ip, DB, account))
{
CreateNewSession(ip, DB, account);
}
AccountsSession sessionsToDelete = DB.AccountsSessions.Where(a => a.RemoteIP == ip && a.AccountID == 1).FirstOrDefault();
if (sessionsToDelete != null)
{
DB.DeleteObject(sessionsToDelete);
DB.SaveChanges();
}
}
I've also tried it with these options:
DB.DeleteObject(sessionsToDelete);
DB.SaveChanges(System.Data.Objects.SaveOptions.DetectChangesBeforeSave);
DB.AcceptAllChanges();
I also started with no using block and just and instantiated entity object, but that didn't work either.
I love issues like this.
Most of the times that I have seen an ORM not execute a command (and without error) is due to changes to the underlying data tables that aren't represented in the generated classes for that table.
You might refresh your schema / class model and try again.
Carrying on from Chris' answer the other thing I've found in the past is if you are doing EF database first modelling then you may have created the foreign keys linking two associated tables but the key hasn't been set as delete cascade in the relationship. This can cause EF to be a little difficult. So check any FKs in your db. Hope that helps.