how does .AttachAll() work for updating and inserting - c#

This question is pretty simple , but I can't seem to get a clear answer from MSDN docs.
I have a list of objects that map to a table in my database. Some of these objects have the ID filled out, some don't. I want to use something like
myContext.myTable.AttachAll(myList);
now , I was hoping that the objects that have an ID - which is Primary Key in the database will get attached and perform an update to those rows, and my objects that don't have an ID will be treated like an INSERT , and the db will automatically create an ID. Is that how this works?

Taken from documentation:
This method attaches all entities of a collection to the DataContext
in either a modified or unmodified state. If attaching as modified,
the entity must either declare a version member or must not
participate in update conflict checking. If attaching as unmodified,
the entity is assumed to represent the original value. After calling
this method, the entity's fields can be modified with other
information from the client before SubmitChanges is called. For more
information, see Data Retrieval and CUD Operations in N-Tier
Applications (LINQ to SQL).
When a new entity is attached, deferred loaders for any child
collections (for example, EntitySet collections of entities from
associated tables) are initialized. When SubmitChanges is called,
members of the child collections are put into an Unmodified state. To
update members of a child collection, you must explicitly call Attach
and specify that entity.

Related

NavigationProperty null on added foreign key

Whenever I add a foreign key entity to my previous entity by setting the ForeignKey-ID, the associated object is null.
Let me explain this:
In a previous step I've set the AddressId property to 28 and have saved the entity context by calling context.SaveChanges().
Now why is AddressId filled, but Address as the NavigationProperty (which should be an Address object of the Address table where Address.Id == 28) is null?
Entity Frameworks (EF) work this by design.
Updating the foreign key never updates the navigation property.
However, updating the navigation property will update the key. Also note that in this case the Address entity should come from the same context. If not .SaveChanges() will consider the Address entity as new and try to add it in the database.
As to the question of which method is better, well, it depends!
- Updating the Key is straightforward and is what we have been doing all along using Data Transfer Objects (DTOs) or even plain SQL. So is easier for newcomers to EF to grasp and use.
- Updating the navigation property is where you truly get an object based data model. The code looks cleaner and more readable. However you need to be very careful with the Context. In my little personal experience with EF, I find that trying to update the navigation property brings more complexity than value, especially in a multi-tier architecture where the Context is hidden behind the Data Access layer.
The most important benefit of EF, in my opinion, is in query operations using LINQ-to-Entities. I have compile-time syntax check for my queries and strong typing. I can easily create an object-based result set with multiple levels of children, data-bind ready without any additional code. I rarely write SQL anymore.
I sorta fixed this by re-creating my entities and reloading then. This seems to work and re-fetch the n:m relationship navigation properties. Weird.

EF code first: How to delete a row from an entity's Collection while following DDD?

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.

What should I call a method checking if two entities refers the same db entity?

I have entity objects that are synchronized with a database. I commonly use these entities in three different comparisons:
Check if two entity objects are the same CLR object.
Check if all properties of two entity objects are equal.
Check if two entity objects refer to the same database entity, even if some properties differ.
For 1 I use Object.ReferenceEquals().
For 2 I overwrite Equals() checking all properties.
For 3 I have been a bit inconsistent. Some entities have a "Match" method some have a "IsSame" method. The logic of the method compares their primary key and if has not been assigned by the database yet, their secondary key (if they have one).
A lot of code scenarios would be easier if I used Equals for comparing keys (e.g. I could check a list just using Contains()), but I would find it confusing, if Equals only compared the keys and didn't check all properties.
My scenario is an N-Tier system with self-tracking-entities. I often need to update a list of entities or similar with an updated entity arriving from another tier.
Is there a consensus for naming a method checking if two entities refers to the same logical entity? KeyEquals()? SameEntity()?
DbEquivalent()?

Add/Update a list of entities using the entity framework

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 ).

In LINQ to SQL, is InsertOnSubmit() required when adding via a Foreign Key?

In LINQ to SQL, is InsertOnSubmit() required when adding via a Foreign Key?
I.e. If I have code that does the following, where orders and order lines are linked in the dbml and database via a foreigh key:
Create order.
Add order to datacontext orders.
Create order line.
Add to order.Lines.
Do I still need to add the order line to the context.OrderLine collection?
No, in almost all cases it is not needed if you attach (assigned to property or add to collection of entity) it to an attached object (on that was pulled from the DB). If the root object is disconnected, but all other data relates to it, you only need to insert the root object :)
Kinda cool, hey!

Categories