1

以下に示すように、多対多の関係を持つ2つのエンティティがあります。

public class StandardContact {
    ...
    public virtual ICollection<RelayConfig> RelayConfigs { get; set; }
}

public class RelayConfig {
....
    public virtual ICollection<StandardContact> StandardContacts { get; set; }
}

RelayConfig とその StandardContact との関係を更新しようとしています。Update() メソッドで作成したコードを次に示します。新しい StandardContact を追加したり、既存の StandardContact を削除したりするだけです (ユーザーの要求に応じて)。パラメータ 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);
    }
}

RelayConfigRepositoryで Update メソッドを呼び出すWPF クライアント (ViewModel) 。

[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

トレースは少し不器用でしたが、Update メソッドに関連する特別な手順ステートメントを見ることができました。EF によって生成された関連する SQL ステートメントを次に示します。

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 レコードを更新し、リンク テーブル RelayConfigStandardContact (多対多レコードに追加する新しいレコード) に別のエントリを追加するための SQL があります。しかし、多対多の関係から削除しようとしているリンク テーブル レコードに対して生成された SQL ステートメントはありません。

4

1 に答える 1

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"
        }
    }
}

更新前:

前

更新後:

後

于 2012-11-18T14:18:44.973 に答える