Delete Item from DB using EntityCollection.Remove() - c#

I have master table and details table. For example master table is ObjectSet<'MasterObject> and details table is ObjectSet<'DetailObject>. So each MasterObject contains EntityCollection<'DetailObject>.
As I understand I can remove DetailObject from database using following:
EntityCollection<'DetailObject> ec = masterObject.DetailObjects;
// as navigation property
ec.Remove(deleting_detail_object); // deleting_detail_object will be removed and marked for deleting.
context.SaveChanges(); // I have exception
After Remove() the deleting_detail_object.MasterObject (navigation property) is null. It is normal. But context.SaveChanges() give me following exception :
"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."
I can delete this DetailObject using context.RemoveObject(), but is it possible to do it using EntityCollection<>?

I do not think this problem has something to do with EntityCollection, I think you have a problem with your database schema.
If your master table have a FK to details that is not nullable you cannot remove the detail table row since that would violate your database schema.
Either change it so that the FK can be null or redesign your database schema.
If this is an operation you need to support, maybe you should have a FK in your details table referencing your master table. So, that you can delete detail rows.
If this does not help please supply a script that shows how you create your database tables.

Related

How do you delete a single record from EF, when you're using generics?

I'm having a problem in which the deletion of a record in a table works, but only so long as the table has no child foreign key relationships. Now, when we have a parent table and want to delete the record using EF, it fails with an error of, "The relationship could not be changed because one or more of the foreign-key properties is non-nullable." I've deleted cascading delete on the child table referencing the parent table. I've tested it within SSMS. It works fine. But from within C# it fails. We have a view model where we've defined a generic DeleteRow method. This works great, so long as the row being deleted has no child tables. It fails, if the table is a parent table. I tried looking here on Stackoverflow for an answer and came across this question, now closed: stackoverflow.com/questions/17723276/delete-a-single-record-from-entity-framework. The answer to this question used a discrete table in EF. We're using generics. Here's our code:
public void DeleteRow(T row)
{
if (App.MainDataContext != null && row != null)
{
App.MainDataContext.Entry<T>(row).State = EntityState.Deleted;
App.MainDataContext.SaveChanges();
}
}
I don't believe setting the State property to the enumeration EntityState.Deleted is working, as that's only setting it for the record in the parent table, not for any of the related records in the child tables. (MainDataContext is entity from a .EDMX file.) How do we delete a single record from any table using EF 6 when we're using generics to pass in the table type?
The problem is that when you set the state to deleted, the related entity is also loaded (tracked by the context's change tracker). When you delete your row, EF tries to set the parent navigation property to null, but it is a not nullable relationship.
To solve this you have to set a cascading delete in the relationship in you model (EDMX), not only in the database.
It should work also, if by the instance of your context the related entity is not tracked. In this case on SQL-Server side the cascading delete should work.

The operation failed: The relationship could not be changed because one or more of the foreign-key properties is non-nullable.

This question might look like a duplicate to other similar questions. But I suggest you to read the question till end and then decide if its a duplicate of some post or not?????
I have 6 tables in my database as follows:
I have some records already inserted in all tables.
Now, I am trying to update an Order.
At first, I just tried to Update the order as follows:
CurrentOrder.UpdateOrder(Order);
The UpdateOrder method in OrderClient looks like:
public Order UpdateOrder(Order Order)
{
IOrderRepository OrderRepository = _DataRepositoryFactory.GetDataRepository<IOrderRepository>();
Order updatedEntity = null;
if (Order.OrderId == 0)
{
updatedEntity = OrderRepository.Add(Order);
}
else
{
updatedEntity = OrderRepository.Update(Order);
}
return updatedEntity;
}
And in OrderRepository:
protected override Order UpdateEntity(RateDifferenceContext entityContext, Order entity)
{
return (from e in entityContext.OrderSet
where e.OrderId == entity.OrderId
select e).FirstOrDefault();
}
And then in DataRepositoryBase class I am using the below method:
public T Update(T entity)
{
using (U entityContext = new U())
{
T existingEntity = UpdateEntity(entityContext, entity);
SimpleMapper.PropertyMap(entity, existingEntity);
entityContext.SaveChanges();
return existingEntity;
}
}
At this point I got an error saying:
Multiplicity constraint violated. The role '…' of the relationship '…' has multiplicity 1 or 0..1
So, I thought that I need to delete the records which are specific to this order in all the related tables. So, I tried the below code:
using (var xaction = new TransactionScope())
{
foreach (OrderItemDetail orderItemDetail in OrderItemDetailClient.GetAllOrderItemDetails().Where(x => x.OrderId == NewOrder.OrderId))
{
OrderItemDetailClient.DeleteOrderItemDetail(orderItemDetail);
}
foreach (Dispatch dispatch in DispatchClient.GetAllDispatches().Where(x => x.OrderId == NewOrder.OrderId))
{
foreach (DispatchItemDetail dispatchItemDetail in DispatchItemDetailClient.GetAllDispatchItemDetails().Where(x => x.InvoiceId == dispatch.InvoiceId))
{
DispatchItemDetailClient.DeleteDispatchItemDetail(dispatchItemDetail);
}
DispatchClient.DeleteDispatch(dispatch);
}
OrderClient.UpdateOrder(NewOrder);
xaction.Complete();
}
Now, I get another error saying that :
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.
I get this error on below mentioned line in the last code-block:
DispatchClient.DeleteDispatch(dispatch);
You have two different problems. We don't have enough details to give you a specific fix, but since these are both very common EF "gotchas" I believe it's valuable to walk through what's happening.
The first error:
Multiplicity constraint violated. The role '…' of the relationship '…'
has multiplicity 1 or 0..1
This means your foreign key properties do not match. In EF, you often end up in situations where the same SQL relationship is represented multiple ways in your model.
For example, your Order class may have a collection of OrderItemDetails on it (which is populated using OrderItemDetail.OrderId). Your OrderItemDetail may also have an Order property on it, which is populated using the same foreign key. If both of these properties are marked as changed but the new values don't match, EF doesn't know what new value to save to the OrderItemdetail.OrderId field. In that situation it will throw this exception. The same problem can occur if OrderItemDetail has an Order property and an OrderId property.
To avoid this problem, you have to be very careful which properties you modify. Using property mappers can be dangerous because they can "accidentally" modify the wrong properties and cause lots of problems like this. We would need to see how SimpleMapper works or how that mapping is configured to really troubleshoot.
The second error:
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.
This error typically means that you are not really deleting an object. You are removing the object from a relationship collection, which just sets the foreign key to null.
Continuing with the above example, if you call myOrder.OrderItemDetails.Remove(detail) then call SaveChanges, you may think it will just delete the OrderItemDetail record from the database, but that's not really what you told it to do. You removed it from the list of order item details associated with myOrder. In order to accomplish this, EF generates an UPDATE statement which sets the OrderId column to null. Without more details on your model and code from your DeleteDispatch method it's hard to know exactly where the issue is, but the exception means it's trying to set that foreign key property to null and failing because it's non-nullable.
The "fix" is to remove items directly from the Context collection instead of the related items collection. I.e. instead of myOrder.OrderItemDetails.Remove, you should call context.OrderItemDetails.Remove. This deletes the record for real.

Updating detached EF object with many to many mapping

I have a repository in EF that needs to Update detached entities but ones which exist in the ObjectStateManager. Imagine you have a session open on a DBContext where you have loaded a particular entity, but then you receive a request to update from a detached version of the object. The only way I have found to do this is to GET the existing object in the state manager, then one by one, update the fields to the fields of the passed-in object. Then set the state of the object state manager version to modified, and save the context.
This works for simple entities that don't contain navigation properties.
I am now trying to do so on an entity that has a many-to-many relationship.
Imagine you have a BlogPost object, and a Hashtag object. This is a many to many relationship. I have defined this and in the database I can see I have three tables, the BlogPost, the HashTag and the mapping table.
What I want to be able to do is edit the blog post on the front end, pass in the updated blog post with it's new list of hashtags that apply to it, and update the database.
The problem is the list of hashtags could be completely unrelated to the old one, so I first have to clear out all the previous mappings, then add the new ones in. If they are the same, this will be a necessary redundancy but the only way to achieve it.
I cannot figure out how to clear out the previous mappings in the many to many relationship though. I have tried
foreach (var tag in dbBlogPost.Hashtags)
dbItem.Hashtags.Remove(tag);
I then add the new hashtags to the empty collection, then do
Work.Context.Entry(dbItem).State = EntityState.Modified;
Work.Context.Save();
But when I save the repository, I get the following exception
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.
Can anyone suggest what I am doing wrong?
The DbSet<TEntity>.Local represents a local view of all Added, Unchanged, and Modified entities in this set. So you can clear all the collection before make any change.
dbBlogPost.Hashtags.Local.Clear();

How to cascade delete in entity framework?

I have two objects in my model
Car and carPart
with 1:n relationship.
I want to delete cascade the entity car.
when I delete i get the following exception :
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.
I think it tries to delete the car object first and then the car parts.
Which is imposiible due to the foreign key.
How do I handle this ?
I want, obviously to delete the carPart first and then only the car.
Thanks.
You'll need to tell the database that you want to cascade on delete, and then Entity Framework will do what you expect. You can change the FK behavior if you go to the Relationships screen for a table in SQL Server Management Studio:
If you want Cascade delete then setup cascade delete at database level. You are getting error because SQL is not allowing to deletion.
You don't have to do it in Entity Framework.

Entityframework 4: Problem with ForeignKey when removing a child entity from parents collection

New to the EF, I have an issue.
OK, so, I have an Entity with a related Table (one-to-many relationship). The entity holds a collection of child objects from the related table. I want to remove an object from the related collection but not from the child table.
However, when I call <entity>.myRelatedChildTable.Remove( childEntity ) and then call the _context.SaveChanges( ), I get an exception about ForeignKey Constraints. Now, if I call the _context.DeleteObject() and then _context.SaveChanges() we have no problem. But, now we have no child entity as well--it is deleted from the db.
here is the text of the Exception:
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.
anyone have an idea/suggestion how I can fix this?
It sounds like you're basically trying to decouple EF from the database. Unfortunately save changes pushes the changes back to the database which obviously you don't want. You can just not call SaveChanges and continue to work with the collection. EF will account for your deletion and not return that information. At the end you can discard your changes and move on.
If you do actually want to delete the item without deleting the child you can't in the current schema. You would have to allow nulls in the DB.

Categories

Resources