views:

657

answers:

3

I need some clarification re cascade deletes in Entity Framework and despite searching for hours am no closer to a solution.

In a nutshell, if I have an entity (MyObject) that has a 1->0..1 relationship with a child (MyObjectDetail) then I can't delete MyObject without an UpdateException complaining about constraints - but ONLY IF the child MyObjectDetail is not loaded into memory.

System.Data.UpdateException: A relationship is being added or deleted from an AssociationSet 'FK_MyObjectDetail_MyObject'. With cardinality constraints, a corresponding 'MyObjectDetail' must also be added or deleted.

If the child is loaded (i.e. MyObject.MyObjectDetailReference.Load() before deleting the MyObject) then it works fine.

My issue is, of course, that I don't want to (read: cannot) load the varbinary field from MyObjectDetail everytime I want to delete the parent MyObject. Is this possible, or am I going to have to hack in some manual SQL calls to make this work?

In SQL server:

MyObject [PK:Id<int>] -> MyObjectDetail [PK:MyObjectId<int>, Data<varbinary>]

The relationship is set to "Cascade" for update and delete.

In EF Designer:

MyObject [1] -> [0..1] MyObjectDetail

In EF XML:

SSDL:

        <Association Name="FK_MyObjectDetail_MyObject">
          <End Role="MyObject" Type="MyEntities.Store.MyObject" Multiplicity="1">
            <OnDelete Action="Cascade" />
          </End>
          <End Role="ObjectDetail" Type="MyEntities.Store.ObjectDetail" Multiplicity="0..1" />
          <ReferentialConstraint>
            <Principal Role="MyObject">
              <PropertyRef Name="Id" />
            </Principal>
            <Dependent Role="ObjectDetail">
              <PropertyRef Name="MyObjectId" />
            </Dependent>
          </ReferentialConstraint>
        </Association>

CSDL:

     <Association Name="FK_MyObjectDetail_MyObject">
          <End Type="MyEntities.MyObject" Role="MyObject" Multiplicity="1">
            <OnDelete Action="Cascade" />
          </End>
          <End Type="MyEntities.MyObjectDetail" Role="ObjectDetail" Multiplicity="0..1" />
          <ReferentialConstraint>
            <Principal Role="MyObject">
              <PropertyRef Name="Id" /></Principal>
            <Dependent Role="ObjectDetail">
              <PropertyRef Name="MyObjectId" />
            </Dependent>
          </ReferentialConstraint>
      </Association>

(The <OnDelete> in the CSDL having been added by me manually as per articles like http://codepolice.net/2008/12/16/cascade-delete-in-entity-framework/)

Am I doing anything wrong, or is this simply not possible in v1 of the EF?

+1  A: 

i think you can get around this by updating the myObject.myPropertyReference = new EntityKey with the id of the related object.. something like:

myObject.myPropertyReference.EntityKey = EFExtensions.GetEntityKey(context, "myObjectID", myObject.myObjectID);

search for EFExtension .. you don't need this as there is a way to create the EntityKey without it.

hope that helps!

Brilliant. This does what I was looking for perfectly - thanks! Instead of the EFExtensions, I just used: EntityKey = new EntityKey("MyEntities.MyObjectDetailSet", "MyObjectId", id)
dkr88
+1  A: 

The EF relies on the database doing the cascade delete.

The exception is when the child entity is in memory. Then the EF will delete it too, not to satisfy the cascade delete rule. But rather because it needs to do so to keep the ObjectContext in sync with what it expects the database to look like after the Principal is deleted in the database.

What this means is if you don't have a cascade setup in the database, and the dependent entities are not loaded, the EF won't delete them when you delete the principle, because it assumes the database will do it.

See Tip 33 - How cascade delete really works for more information.

Does this help?

Alex James

Entity Framework Team

Alex James
So, what changes do we need to make to get this situation to "just work"?
DoctaJonez
A: 

This blog entry actually references this question as an example of the problem for which it presents a solution.

Simon_Weaver