开发者

EF 4.1 Code First: Trigger update of many-to-many

I have an entity, BusinessUnit, which has a many-to-many relationship with a Contact entity. We're using Fluent configuration as per the sample below:

public BusinessUnitConfiguration()
{
    HasMany(c => c.Contacts)
        .WithMany()
        .Map(m =>
            {
                m.ToTable("BusinessUnitContact");
                m.MapLeftKey("BusinessUnitId");
                m.MapRightKey("ContactId");
            });

    ToTable("BusinessUnit");
}

public ContactConfiguration()
{
    ToTable("Contact");
}   

The Contact entity has no idea what parents it may be related to. We are using Silverlight + WCF, so lazy loading and proxy creation is disabled.

We create or modify an object graph on the client consisting of a BusinessUni开发者_运维百科t instance and zero or more Contact instances, then send to a WCF service to save, where a new context is created and we add / attach / remove as necessary before saving changes.

The problem is that if I add a new contact to the Contacts collection on an existing business unit, EF does not insert a junction record - it knows to add the new Contact, because I've added it, but not the BusinessUnitContact row that maps the business unit to the contact.

The Contacts property on BusinessUnit is an ObservableCollection<Contact>. It works when the parent business unit is added, but not when it is attached.

Is there a way that I can tell EF to modify the Contacts association when attaching it to a context, so that it will work out what new junction records need to be inserted?


I found the problem. The code that was attaching the parent entity to the EF context was not actually attaching it directly - it was loading the original entity, then merging in the properties from the entity being attached:

// attach entity
var existing = GetQuery<TEntity>().FirstOrDefault(e => e.Id == entity.Id);
if (existing == null)
{
   throw new InvalidOperationException("Cannot attach an entity that does not exist in the database.");
}

switch (entity.State)
{
    case ObjectState.Modified:
        GetEntry(existing).CurrentValues.SetValues(entity);
        break;

    case ObjectState.Deleted:
        GetEntry(existing).State = EntityState.Deleted;
        break;
}

This doesn't seem to work for navigation properties though, so I changed the code to be the following:

var set = GetSet<TEntity>();
set.Attach(entity);

// map object state to entity state
switch (entity.State)
{
    case ObjectState.Modified:
        GetEntry(entity).State = EntityState.Modified;
        break;

    case ObjectState.Deleted:
        GetEntry(entity).State = EntityState.Deleted;
        break;
}

All that needed to change was making sure the entity being attached was the same as the entity coming in - the BusinessUnit entity doesn't have to be modified either.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜