Writing a unit test I have a ContactEntity and an EmailEntity. I have tried every possible scenario of the Association Attribute I can think of and I can't get this to happen...

  1. create contact,
  2. add email to contact (x3),
  3. save contact,
  4. remove email,
  5. save contact,
  6. remove email,
  7. save contact,
  8. remove email,
  9. save contact,

Assert - Table Emails -> Count == 0

The three emails are always left in the database. They're not assigned to the contact any longer and I do admit I think the application would run fine. Meaning if I load up my contact now, it doesn't have any emails. In my mind however, these emails are orphaned and should not be in the table.

Help?

[HierarchyRoot]
[TableMapping("Contacts")]
public partial class ContactEntity : BaseEntity//, IIdentifiable<int>
{
    [Key, Field]
    public int Id { get; private set; }

    [Field(Length = 30)]
    public string First { get; set; }
    [Field(Length = 50)]
    public string Last { get; set; }
    [Field(Length = 30)]
    public string Nick { get; set; }
    [Field]
    public string Website { get; set; }
    [Field(Nullable = true)]
    public AddressEntity Address { get; set; }

    [Field]
    public EntitySet<EmailEntity> Emails { get; set; }

    [Field]
    public EntitySet< PhoneEntity > Phones { get; set; }

}

[HierarchyRoot]
[TableMapping("Emails")]
public partial class EmailEntity : BaseEntity//, IIdentifiable<int>
{
    [Key, Field]
    public int Id { get; private set; }

    [Field]
    public EmailType Type { get; set; }
    [Field(Length = 320)]
    public string Address { get; set; }
    [Field]
    public bool IsPublic { get; set; }
    //[Association(PairTo = "Emails")]
    [Field]
    [Association(PairTo = "Emails", OnOwnerRemove = OnRemoveAction.Cascade, OnTargetRemove = OnRemoveAction.Default)]
    public ContactEntity Contact { get; set; }

}

asked Oct 04 '13 at 17:52

Dave%20Jellison%20Fabnu's gravatar image

Dave Jellison Fabnu
9336

edited Oct 04 '13 at 18:02

Dmitri%20Maximov's gravatar image

Dmitri Maximov
22111211

They also seem to remain after I remove the contact. Also, I'm trying to handle DTO<-->Entity mapping (you may have guessed), what's the preferred method of iterating an EntitySet and removing certain items? I'm building an id list, then looping, then removing, feels kinda clunky.

(Oct 04 '13 at 18:05) Dave Jellison Fabnu Dave%20Jellison%20Fabnu's gravatar image

I lied, Cascade+Cascade worked, sorry. I swore I tried this before and it threw an exception.

(Oct 04 '13 at 18:09) Dave Jellison Fabnu Dave%20Jellison%20Fabnu's gravatar image

2 Answers:

Hello Dave,

probably you're removing e-mail from entity set instead of removing the e-mail object itself. Removing item from entity set simply breaks the relation (in your case by setting Email.Contact to null).

However removing the e-mail itself will trigger on-remove actions according to [Association] attribute.

Here is an example on-remove action configuration that is likely suits your needs:

[Field]
[Association(PairTo = "Emails",
  OnOwnerRemove = OnRemoveAction.Clear, OnTargetRemove = OnRemoveAction.Cascade)]
public ContactEntity Contact { get; set; }

Removing ContactEntity object will remove all associated e-mails. However removing EmailEntity object will only remove that object from corresponding ContactEntity.Emails.

answered Oct 04 '13 at 18:07

Denis%20Krjuchkov's gravatar image

Denis Krjuchkov
179325

Thanks, cascade+cascade worked also, but I didn't find it very intuitive, this works also and makes more sense. I think I must have gone a little schitzo when going to/from each entity with the association attribute. Thanks Denis!

(Oct 04 '13 at 18:11) Dave Jellison Fabnu Dave%20Jellison%20Fabnu's gravatar image
    [Field]
    [Association(PairTo = "Emails", OnOwnerRemove = OnRemoveAction.Cascade, OnTargetRemove = OnRemoveAction.Cascade)]
    public ContactEntity Contact { get; set; }

answered Oct 04 '13 at 18:09

Dave%20Jellison%20Fabnu's gravatar image

Dave Jellison Fabnu
9336

Dear Dave,

Please consider posting comments to the same thread instead of answers, in case you are not giving an alternative answer, of course. This will definitely help other readers to follow the thread of discussion.

Thanks

(Oct 04 '13 at 18:13) Dmitri Maximov Dmitri%20Maximov's gravatar image
1

I'm fluent with SO (StackOverflow) and the site struct -> this was my solution (and works) however Denis' solution is the correct approach. Thanks

(Oct 04 '13 at 18:24) Dave Jellison Fabnu Dave%20Jellison%20Fabnu's gravatar image
Your answer
Please start posting your answer anonymously - your answer will be saved within the current session and published after you log in or create a new account. Please try to give a substantial answer, for discussions, please use comments and please do remember to vote (after you log in)!
toggle preview

powered by OSQA