我有两个具有多对多关系的实体,如下所示。
public class StandardContact {
...
public virtual ICollection<RelayConfig> RelayConfigs { get; set; }
}
public class RelayConfig {
....
public virtual ICollection<StandardContact> StandardContacts { get; set; }
}
我正在尝试更新RelayConfig及其与StandardContact的关系。这是我在Update()方法中提出的代码。它只是添加了一些新的StandardContact和/或删除了现有的StandardContacts(根据用户的要求)。参数exposedContacts表示应在数据库中更新的全包式StandardContacts列表
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); });
}
正确地添加了与RelayConfig相关的新StandardContact实体。但是,删除(上面代码中的最后一行)没有任何效果,并且链接表中的“多对多”关系保持不变。
简而言之,我无法从RelayConfig对象中删除StandardContact实体。我没有得到任何例外,但代码仍然存在。
更新
以下是与数据库相关的代码:
RelayContext类
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);
}
}
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);});
}
....
}
UnitOfWork类
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);
}
}
WPF客户端(ViewModel),它在RelayConfigRepository上调用Update方法。
[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);
}
}
更新2
跟踪有点笨拙,但我可以看到与更新方法相关的特殊程序声明。以下是EF生成的相关SQL staments。
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**
正如您所看到的,有用于更新RelayConfig记录和在链接表中添加另一个条目的SQL RelayConfigStandardContact(我在多对多记录中添加的新记录)。但是没有为我从多对多关系中删除的链接表记录生成SQL语句。
答案 0 :(得分:0)
测试程序以显示它应该按预期工作:
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
namespace EFDelMany
{
public class StandardContact
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<RelayConfig> RelayConfigs { get; set; }
}
public class RelayConfig
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<StandardContact> StandardContacts { get; set; }
}
public class MyContext : DbContext
{
public DbSet<StandardContact> StandardContacts { get; set; }
public DbSet<RelayConfig> RelayConfigs { get; set; }
}
class Program
{
static void Main(string[] args)
{
Database.SetInitializer(new DropCreateDatabaseAlways<MyContext>());
using (var context = new MyContext())
{
context.Database.Initialize(true);
// Create one RelayConfig and 5 StandardContacts
var relayConfig1 = new RelayConfig { Name = "R1" };
var standardContact1 = new StandardContact { Name = "S1" };
var standardContact2 = new StandardContact { Name = "S2" };
var standardContact3 = new StandardContact { Name = "S3" };
var standardContact4 = new StandardContact { Name = "S4" };
var standardContact5 = new StandardContact { Name = "S5" };
// Create relationship for StandardContacts 1,2,3
relayConfig1.StandardContacts = new List<StandardContact>
{
standardContact1,
standardContact2,
standardContact3
};
context.RelayConfigs.Add(relayConfig1);
context.StandardContacts.Add(standardContact4);
context.StandardContacts.Add(standardContact5);
context.SaveChanges();
}
// see screenshot "Before"
RelayConfig relayConfig = new RelayConfig { Id = 1, Name = "R1a" };
List<StandardContact> exposedContacts = new List<StandardContact>
{
// delete relationship to StandardContacts 1 and 3
new StandardContact { Id = 2 }, // keep relationship to StandardContact 2
new StandardContact { Id = 4 }, // add relationship to StandardContact 4
new StandardContact { Id = 5 } // add relationship to StandardContact 5
};
using (var context = new MyContext())
{
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); });
context.SaveChanges();
}
// see screenshot "After"
}
}
}
之前更新:
更新后: