I have a model called 'target' retreived by entityframework with a collection addresses.
After removing all items that are not in excesting in another collection i'm saving my entity framework context.
However, when checking my database the records are still there. While my linq code made sure to remove the items from the collection.
Here is my linq code:
using (IUnitOfWork uow = _uow.CreateUnitOfWork())
{
var target = _repository.GetByBron(uow, bron.BronId);
target.Adressen.RemoveAll(x => source.Adressen.All(y => !y.Equals(x)));
//Which calls Context.SaveChanges(); inside the unit of work class
uow.Save(_logger);
}
Update: The problem is not removing my record from the collection. Its when i'm calling the save on the context. The relation record in my database is still there... nothing has been deleted... aldo it was removed from the collection.
Solved
I'm directly removing it from the context now. (with a seperated repository object)
This is very dependent upon the configuration of the relationships. See Entity Framework .Remove() vs. .DeleteObject()
Since your relationship sounds to be a many to many, you will likely need to call DeleteObject for the addresses themselves, as EF won't automatically delete the orphaned records.
Related
I have this problem where I have 2 entities connected by foreign key.
AEntity: id, idOfEntityB (foreign key, constraint), fields...
BEntity: id, fields...
I save both of them to the database with SaveChanges(), later when I try to get AEntity's idOfEntityB, I succeed but when I try to get BEntity according to the id I got from AEntity, I get nothing:
context.AEntities.Add(new AEntity {
BEntity = new BEntity { ... }
});
context.SaveChanges();
.
.
.
var id1 = context.AEntities.Select(x => x.idOfEntityB);
var bEntities = context.BEntities.Where(x => id1.Contains(x.id));
bEntities has nothing in it. but the fact I was able to have values in id1 is even more confusing since they have foreign key relations (with constraint) and furthermore, id could not be created if it was not saved to the DB.
Later, when I look in the DB I see both entities as should be.
It happens sometimes and I cant reproduce the problem, I cant give more then this as an example since there's a lot of code, I believe it has something to do with caching, and therefore would like to ask if something like that is possible or not and how.
is there a way entities are saved to the DB while the context (a different one used from the context that saved) does not hold all of them in completion?
This is likely the issue you are encountering if you are relying on seeing changes between state changes between different DbContext instances. When a DbContext has loaded entities, then another DbContext instance makes changes to those records or the records change behind the scenes in the database, that original DbContext will not refresh the entities from the database.
EF does support the ability to reload entities from the database, but when dealing with child collections it gets a bit more complicated to perform a full refresh. You effectively need to tell the DbContext to forget all of the child collections, stop tracking the parent, clear the parent's child collection, then re-attach and reload the child collection. I recently covered this in the answer for this question: Replacing a entity collection in Entity Framework Core causes DbContext to fetch the new values when not saved to db. How to reload the collection?
Ultimately a DbContext lifespan should be kept as short as possible.
I have a Project object, which consists of many nested objects.
To save this object to the DB:
I change just one property within my Project (as a test), and pass it to my DAL.
I load the existing Project from the DB with EF.
I map the changed Project to the existing Project.
var existingProject =
db.Project.Single(p => p.ID == changedProject.ID).Include(p => p.Something);
existingProject = Mapper.Map(changedProject, existingProject);
db.SaveChanges();
This fails due to null foreign keys, which is no surprise because when I drill into the change tracker, I can see it's very confused:
var added = db.ChangeTracker.Entries().Where(e => e.State == EntityState.Added);
After the mapping takes place, a huge number of objects within the Project are marked as Added (even though nothing has been added or deleted from the project, I've only changed one property).
Is this because AutoMapper creates new instances of nested objects, and EF can't associate these with the existing objects from the DB?
I've seen this approach suggested in numerous places, is there a way for AutoMapper to work with the ChangeTracker so it understands the above - or is it better to just map everything manually? (a lot of work, in my case)
Destination collections are cleared first. You need AutoMapper.Collection if you want to map to existing EF collections.
This is because when You are mapping, new entity is created and EF context does not have any information about it.
You can map data from db to your 'changedProject' do all necessary changes then map again to 'existingProject' and for this entity call 'Update' method like in following example(using System.Data.EntityState.Modified)
Updating records using a Repository Pattern with Entity Framework 6
In EF 6, to remove entities from a collection without actually fetching the collection, I am using:
manager.ChangeRelationshipState(entity, wrappedIdOfRelatedEntity, e => e.Collection, EntityState.Deleted);
It works for M:N relationships. But in case of 1:N, it throws the following error:
The ChangeRelationshipState method is not supported for relationships that are defined by using foreign-key values.
Just to clarify, I do not want to fetch the collection, since it may be really huge, moreover I do not want to fetch the entities that should be removed.
I have the key (id) of the entity that 'contains' the collection and keys (ids) of the entities that should be removed.
Any hints, how to do it correctly?
NOTICE: Adding is possible by just adding wrapped entity keys to a collection. But removing is causing the problem.
Do you use row versioning/timestamp on your entities? If you do, EF needs to version because it's doing to send an update statement containing both the id and version of the entity to delete.
If you're not using row versioning/timestamp on your entities, you can do the following using the DbContext API but you need to use proxies and change detection.
Recreate the entities you want to remove from the collection by using DbSet.Create
Populate the recreated entities with the id of the entities you want to remove
Attach the entities using DbSet.Attach
Add the entities to the collection and then call AcceptAllChanges on the ObjectContext to reset the state of the entites
Remove the entities from the collection
Call save changes and it should issue update statements to remove the entities from the collection.
If you're using row versioning/timestamp on your entities, you can use the steps above, but in step 2, you need to set both the version and the id.
So here's the scenario:
DDD states that you use a repository to get the aggregate root, then use that to add/remove to any collections it has.
Adding is simple, you simple call .Add(Item item) on the Collection you wish to add to. A new row is added to the database when you save. However, deleting is different - calling .Remove(Item item) doesn't remove the item from the database, it simply removes the foreign key. So while, yes, it is technically no longer part of the collection anymore, it's still in the database.
Reading around, the only solution is to delete it using the data context. But according to DDD the domain object shouldn't be aware of the data context so therefore deleting will have to be done outside of the domain.
What is the right way to go about this? Or Is leaving the database full of orphans acceptable (perhaps running a routine to clear them out)?
I've solved this problem in the application I'm currently working on by using domain events; a DDD concept Eric Evans said should have been in his book.
While domain objects aren't allowed to know about the object context, an IDomainEventHandler is - I've therefore got a DomainObjectDeletionHandler which deletes 'removed' objects from the object context before control returns to my application layer and the changes are saved.
For more information, I've written a blog about my implementation of domain events and how I approached hooking everything together.
Hope that helps :)
Edit
For example, if you have an Order class which has an OrderItems collection of type OrderItem:
public class Order
{
// Other stuff
public void RemoveOrderItem(int orderItemId)
{
var orderItemToRemove = OrderItems.First(oi => oi.Id == orderItemId)
OrderItems.Remove(orderItemToRemove);
DomainEvents.Raise(new OrderItemRemoved(orderItemToRemove));
}
}
When removing a child entity from a collection, EF will leave it as orphan, removing just the foreign key.
If you don't want to explicitly remove it using the DbContext, you can use what it is called "Identifying Relationship" (http://msdn.microsoft.com/en-us/library/ee373856.aspx at the bottom).
The trick is to set a composite primary key on the child including the parent's primary key.
Once you do that, when removing the entity from the parent's collection, it will be removed from the table as well.
I do not know if this is by design, but if a detail object has a composite key containing its master object's key columns, it will be automatically deleted if you remove it from the master object's collection. If you have an Order object with an OrderID key and ICollection OrderLines navigation property, give OrderLine a composite key containing OrderID and OrderLineID.
But since I do not know if I can rely on that, the solution I've used myself is to let EF handle it the way it does, and fix up 'detached' (not in EF terms) detail objects on the call to SaveChanges(), enumerating over all modified entities and changing the state to deleted as appropriate.
I solved this scenario by configuring the reference column as required and the delete behavior as Cascade
Example:
modelBuilder.Entity<AggregateRoot>()
.HasMany(x => x.Items)
.WithOne()
.IsRequired()
.OnDelete(DeleteBehavior.Cascade);
In this case, EF Core (6.x) no longer set the reference column to NULL, but deleted the record just by removing the Item from the Items collection of the aggregate root.
The decisive configuration here was the delete behavior Cascade.
Why not use two repositories?
var parent = ParentRepo.Get(parentId);
parent.Children.Remove(childId); // remove it from the property Collection
ChildRepo.Delete(childId); // delete it from the database
ParentRepo.Commit(); // calls underlying context.SaveChanges()
Assuming you're sharing contexts via IOC/DI, calling commit with one repo will commit for both, otherwise just call ChildRepo.Commit as well.
I'm returning a List (own class) from Silverlight to a service, in this list there are old entities with updated values and completely new entities, how do I save this back to the database using the entity framework?
Using cEnts.CardItems.AddObject gives me duplicates obviously.
You want to use Attach() instead of AddObject().
Attach will take your disconnect object and let the container know to consider it for updates. The new objects, without a PrimaryKey, will be added.
If you are using the same entity context for selecting and update/insert you have to call AddTo...() method to insert the new entities and ApplyPropertyChanges to the changed ones.
If you are using different contexts the problem is more complicated because you have to detach entities from one context and attach them to another. Once detached entities lose their changed state and you have to explicitly specify which properties have been changed (For more info check this: http://www.abadjimarinov.net/blog/2009/12/13/AttachAlreadyChangedObjectToADataContextInEntityFramework.xhtml ).