I have two entities which have Many-To-Many relationship as given below.
public class StandardContact {
...
public virtual ICollection<RelayConfig> RelayConfigs { get; set; }
}
public class RelayConfig {
....
public virtual ICollection<StandardContact> StandardContacts { get; set; }
}
I am trying to update RelayConfig and its relationship with StandardContact. Here is the code that I have put up in an Update() method. It just adds some new StandardContact and/or deletes existing StandardContacts (as requested by user). The parameter exposedContacts represent the all-inclusive List of StandardContacts that should be updated in database
public void Update(RelayConfig relayConfig, List<StandardContact> exposedContacts) {
RelayConfig dbRelayConfig = context.RelayConfigs.Include(r => r.StandardContacts)
.Where(r => r.Id == relayConfig.Id).SingleOrDefault();
context.Entry<RelayConfig> (dbRelayConfig).CurrentValues.SetValues(relayConfig);
List<StandardContact> addedExposedContacts =
exposedContacts.Where(c1 => !dbRelayConfig.StandardContacts.Any(c2 => c1.Id == c2.Id)).ToList();
List<StandardContact> deletedExposedContacts =
dbRelayConfig.StandardContacts.Where(c1 => !exposedContacts.Any(c2 => c2.Id == c1.Id)).ToList();
StandardContact dbExposedContact = null;
addedExposedContacts.ForEach(exposedContact => {
dbExposedContact = context.StandardContacts.SingleOrDefault(sc => sc.Id == exposedContact.Id);
dbRelayConfig.StandardContacts.Add(dbExposedContact);
});
deletedExposedContacts.ForEach(exposedContact => { dbRelayConfig.StandardContacts.Remove(exposedContact); });
}
The addition of the new StandardContact entities related to RelayConfig is taking place properly. However, the deletion (last line in the code above) has no effect and the Many-To-Many relation in the link table remains as it is.
In short I am not able to remove StandardContact entities from an RelayConfig object. I don't get any exceptions and the code runs through though.
Update:
Here is the code related to Database:
The RelayContext class
public class RelayContext : DbContext {
public DbSet<Station> Stations { get; set; }
public DbSet<StandardContact> StandardContacts { get; set; }
public DbSet<RelayConfig> RelayConfigs { get; set; }
public DbSet<StandardRelay> StandardRelays { get; set; }
public DbSet<Rack> Racks { get; set; }
public DbSet<Group> Groups { get; set; }
public DbSet<Relay> Relays { get; set; }
public DbSet<Contact> Contacts { get; set; }
public RelayContext() {
Database.SetInitializer(new RelayContextInitializer());
}
protected override void OnModelCreating(DbModelBuilder modelBuilder) {
modelBuilder.Entity<Rack>().HasOptional<RelayConfig>(r => r.DefaultFirstRelayConfig).WithMany(rc => rc.RacksWithDefaultFirstRelay).WillCascadeOnDelete(false);
modelBuilder.Entity<Rack>().HasOptional<RelayConfig>(r => r.DefaultSecondRelayConfig).WithMany(rc => rc.RacksWithDefaultSecondRelay).WillCascadeOnDelete(false);
}
}
The RelayConfigRepository
public class RelayConfigRepository {
internal RelayContext context;
public RelayConfigRepository(RelayContext context) {
this.context = context;
}
....
public void Update(RelayConfig relayConfig, List<StandardContact> exposedContacts) {
RelayConfig dbRelayConfig = context.RelayConfigs.Include(r => r.StandardContacts)
.Where(r => r.Id == relayConfig.Id).SingleOrDefault();
context.Entry<RelayConfig> (dbRelayConfig).CurrentValues.SetValues(relayConfig);
List<StandardContact> addedExposedContacts =
exposedContacts.Where(c1 => !dbRelayConfig.StandardContacts.Any(c2 => c1.Id == c2.Id)).ToList();
List<StandardContact> deletedExposedContacts =
dbRelayConfig.StandardContacts.Where(c1 => !exposedContacts.Any(c2 => c2.Id == c1.Id)).ToList();
StandardContact dbExposedContact = null;
addedExposedContacts.ForEach(exposedContact => {
dbExposedContact = context.StandardContacts.SingleOrDefault(sc => sc.Id == exposedContact.Id);
dbRelayConfig.StandardContacts.Add(dbExposedContact);
});
deletedExposedContacts.ForEach(exposedContact => { dbRelayConfig.StandardContacts.Remove(exposedContact);});
}
....
}
The UnitOfWork class
public class UnitOfWork : IDisposable {
private RelayContext context = new RelayContext();
private bool disposed = false;
private RelayConfigRepository _relayConfigRepository;
public RelayConfigRepository RelayConfigRepository {
get {
if (_relayConfigRepository == null) {
_relayConfigRepository = new RelayConfigRepository(context);
}
return _relayConfigRepository;
}
}
private StandardContactRepository _standardContactRepository;
public StandardContactRepository StandardContactRepository {
get {
if (_standardContactRepository == null) {
_standardContactRepository = new StandardContactRepository(context);
}
return _standardContactRepository;
}
}
public void Save() {
try {
context.SaveChanges();
}
catch (DbUpdateConcurrencyException ex) {
throw new RepositoryException(ErrorMessages.UpdateConcurrencyError);
}
catch (Exception ex) {
throw new RepositoryException(ErrorMessages.GeneralError);
}
}
protected virtual void Dispose(bool disposing) {
if (!this.disposed) {
if (disposing) {
context.Dispose();
}
}
this.disposed = true;
}
public void Dispose() {
Dispose(true);
GC.SuppressFinalize(this);
}
}
The WPF Client(ViewModel) Which Calls the Update method on RelayConfigRepository.
[Export(typeof(RelayConfigEditViewModel))]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class RelayConfigEditViewModel :Screen {
private RelayConfig _relayConfig;
public RelayConfig RelayConfig {
get { return _relayConfig; }
set { _relayConfig = value; NotifyOfPropertyChange(() => RelayConfig); }
}
private ObservableCollection<StandardContact> _standardContacts = new ObservableCollection<StandardContact>();
public ObservableCollection<StandardContact> StandardContacts {
get { return _standardContacts;}
set { _standardContacts = value; NotifyOfPropertyChange(() => StandardContacts); }
}
....
public void Save() {
List<StandardContact> exposedContacts = StandardContacts.Where(sc => sc.IsMarked).ToList();
try {
using (UnitOfWork unitOfWork = new UnitOfWork()) {
if (editMode == EditMode.Add) {
unitOfWork.RelayConfigRepository.Insert(RelayConfig, exposedContacts);
}
else {
unitOfWork.RelayConfigRepository.Update(RelayConfig, exposedContacts);
}
unitOfWork.Save();
}
}
catch (Exception ex) {
HandleException(ex);
}
events.Publish(RelayConfig);
}
}
Update 2
Tracing was a bit clumsy, but I could see the special procedure statements relating to the Update Method. Here are the relevant SQL staments generated by EF.
update [dbo].[RelayConfigs]
set [Name] = @0, [DisplayName] = @1
where (([Id] = @2) and ([Version] = @3))
**exec sp_executesql N'insert [dbo].[RelayConfigStandardContacts]([RelayConfig_Id], [StandardContact_Id])
values (@0, @1)
',N'@0 int,@1 int',@0=1,@1=4**
As you can see there is SQL for updating RelayConfig record and for adding another entry in the link table RelayConfigStandardContact (a new record that I am adding in many-to-many record). But there is no SQL statement generated for the link table record that I am removing from the many-to-many relationship.