简体   繁体   English

实体框架6 Code First一对多可选关系删除子问题

[英]Entity framework 6 Code First one-to-many optional relationship remove child issue

I'm currently working on a small application with WPF, EF6 and SqlServer 2012. I have two entities "Region" and "BctGouvernorats" associated with an optional one to many relationship. 我目前正在使用WPF,EF6和SqlServer 2012开发一个小应用程序。我有两个实体“Region”和“BctGouvernorats”与可选的一对多关系相关联。

My problem is : When I remove a child from the relationship (BctGouvernorat), it still appears in the collection related to the parent (Region). 我的问题是:当我从关系中删除一个孩子(BctGouvernorat)时,它仍然出现在与父(Region)相关的集合中。 here's the code: 这是代码:

//Entities
public partial class BctGouvernorat
{
    public long GovId { get; set; }
    public string Libelle { get; set; }
    public long UserId { get; set; }
    public Nullable<long> RegionId { get; set; }
    public virtual Region Region { get; set; }
}

public partial class Region
{
    public long     RegionId { get; set; }
    public string   Libelle { get; set; }
    public long     GroupeNumber { get; set; }
    public byte     Bonus { get; set; }
    public long     UserId { get; set; }
    public virtual  RegionsGroupes GroupeRegions { get; set; }
    public virtual  ICollection<BctGouvernorat> Gouvernorats { get; set; }

    public Region()
    {
        Libelle = "New region";
        GroupeNumber = 0;
        this. Gouvernorats = new HashSet<BctGouvernorat>() ;
    }


//C# code for "Modify" Method
public void Modify(Region r, List<BctGouvernorat> _ToUnlink,    List<BctGouvernorat> _ToLink)
   {
//Below the code for unlink child from parent
       if (_ToUnlink.Count > 0)
       {
           r.Gouvernorats.ToList().All(xx =>
               {
                   if (_ToUnlink.Contains(xx))
                   {
                       xx.RegionId = null;
                       xx.Region = null;
                   }

                   return true;
               }
           );


          }


        //Here the code for link child to the parent
       _ToLink.All(xx =>
           {
               xx.RegionId = r.RegionId;
               xx.Region = r;
               r.Gouvernorats.Add(xx);
               return true;
           });


       //Mark Childs collection as modified
       r.Gouvernorats.All(xx =>
       {
           _uow.GetEntry<BctGouvernorat>(xx).State = EntityState.Modified;
           return true;
       });


         base.Modify(r);

   }

actually the previous method is included in a «RegionRepository» which inherits from a base class Repository. 实际上,前一个方法包含在一个«RegionRepository»中,它继承自基类Repository。 The code of base.Modify() is as follows : base.Modify()的代码如下:

//Method Modify from RegionRepository
public  void Modify(T item)
   {
      _uow.RegisterChanged(item);
      _uow.Commit();
   }   

And The "Modify" Method uses services of a unit of work "_uow" that save data to sqlserver database. 并且“修改”方法使用将数据保存到sqlserver数据库的工作单元“_uow”的服务。 Here the code : 这里的代码:

//***************************
//_uow is a unit of work
//*****************************
 public void RegisterChanged<T>(T item) where T : class
    {
        base.Entry<T>(item).State = System.Data.Entity.EntityState.Modified;

    }


  public void Commit()
    {
        try
        {
            base.SaveChanges();
        }

        catch (DbUpdateException e)
        {
            var innerEx = e.InnerException;
            while (innerEx.InnerException != null)
                innerEx = innerEx.InnerException;
            throw new Exception(innerEx.Message);
        }

        catch (DbEntityValidationException e)
        {
            var sb = new StringBuilder();

            foreach (var entry in e.EntityValidationErrors)
            {
                foreach (var error in entry.ValidationErrors)
                {
                    sb.AppendLine(string.Format("{0}-{1}-{2}",
                    entry.Entry.Entity,
                    error.PropertyName,
                    error.ErrorMessage
                ));
                }
            }
            throw new Exception(sb.ToString());
        }
    }

And mappings : 和映射:

   //Mapping of BctGouvernorat entity

   public BctGouvernoratMapping()
    {
        this.ToTable("BctGouvernorat");
        this.HasKey(t => t.GovId);
        this.Property(t => t.GovId);
        this.HasOptional(t => t.Region)
            .WithMany(t => t.Gouvernorats)
            .HasForeignKey(d => d.RegionId)
            .WillCascadeOnDelete(false);

    }

//Mapping of Region entity
   public RegionMapping()
    {
        this.ToTable("Region");
        this.HasKey(t => t.RegionId);
        this.Property(t => t.RegionId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

    }

and finally viewmodel that calls the code above 最后调用上面代码的viewmodel

private void SaveRegion()
    {
    List<BctGouvernorat> _GovToLink = null;
    //The following method checks and returns (Added, Deleted, Modified BctGouvernorat)
    List<BctGouvernorat> _GovToUnlink = CheckGouvernoratsListStatus(out _GovToLink);
    ILogger _currentLog = (Application.Current as App).GetCurrentLogger();
    using (UnitOfWork cx = new UnitOfWork(_currentLog))
    {
        RegionRepository _regionRepository = new RegionRepository(cx, _currentLog);
        IRegionManagementService rms = new RegionManagementService(_currentLog, _regionRepository);

        if (CurrentRegion.RegionId == 0)
        {
            CurrentRegion.UserId = Session.GetConnectedUser().UserId;
            rms.AddRegion(CurrentRegion);
        }
        else
            rms.ModifyRegion(CurrentRegion, _GovToUnlink,_GovToLink);

    }

}

//The following method checks and returns (Added, Deleted, Modified  BctGouvernorat)
private List<BctGouvernorat> CheckGouvernoratsListStatus(out List<BctGouvernorat> _ToLink)
{

    List<BctGouvernorat> AddedGouvernorats = GouvernoratsRegion.Except<BctGouvernorat>(CurrentRegion.Gouvernorats, 
                                                    new GouvernoratComparer()).ToList();

    _ToLink = AddedGouvernorats;

    List<BctGouvernorat> DeletedGouvernorats = CurrentRegion.Gouvernorats.Except<BctGouvernorat>(GouvernoratsRegion,
                                                    new GouvernoratComparer()).ToList();


    return DeletedGouvernorats;
}


 public void ModifyRegion(Region r, List<BctGouvernorat> _ToUnlik, List<BctGouvernorat> _ToLink)
{
    _regionRepository.Modify(r, _ToUnlik, _ToLink);
}

The "GouvernoratsRegion" is an observablecollection bound to a datagrid that i edit to add or remove BCTgouvernorat Rows to the region “GouvernoratsRegion”是一个observablecollection绑定到一个数据网格,我编辑,以添加或删除BCTgouvernorat行到该区域

Finaly i found a solution. 最后,我找到了解决方案。 The trick is that in this situation : an optional Association one to many with a foreign key : When i want to remove items from childs collection, the parent entity must be first marked as modified, but when i want to link new items to childs collection, the, the parent must be marked after. 诀窍在于:在这种情况下:使用外键可选的一对多关联:当我想从子集合中删除项目时,必须首先将父实体标记为已修改,但是当我想将新项目链接到子集合时,必须在之后标记父母。 here's the code the method modify become as follows : 这里修改方法的代码如下:

  public void Modify(Region r, List<BctGouvernorat> _ToUnlink, List<BctGouvernorat> _ToLink)
   {
   _ToLink.All(xx =>
       {
           xx.RegionId = r.RegionId;
           xx.Region = r;
           _uow.GetEntry<BctGouvernorat>(xx).State = EntityState.Modified;
           r.Gouvernorats.Add(xx);
           return true;
       });

       //The parent entity must be marked as modified here : 
       //  after adding new items but before removing items from collection

  _uow.GetEntry<Region>(r).State = EntityState.Modified;


       if (_ToUnlink.Count > 0)
       {
          r.Gouvernorats.ToList().All(xx =>
               {
                   if (_ToUnlink.Contains(xx))
                   {
                       xx.RegionId = null;
                       xx.Region = null;
                   }

                   return true;
               }
           );
        }


         base.Modify(r);
   }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM