实体框架创建重复实体

时间:2015-11-28 14:27:12

标签: c# entity-framework

首先:我创建了一个数据优先模型!

我有一个m-to-m的关系。为了处理这种关系,我在:

之间增加了一个实体

Player 1 <-> m PlayerLeague m <-> 1 League

我想更新所有玩家联赛(添加/删除)。

到目前为止,这是我的代码:

using (BettingLeagueEntities entities = new BettingLeagueEntities())
        {
            foreach (PlayerCheckBoxList p in this.PlayerList)
            {
                PlayerLeague pl = new PlayerLeague();
                pl.League = this.ActiveLeague;
                pl.Player = p.ActivePlayer;
                entities.PlayerLeague.Add(pl);
            }                
            entities.SaveChanges();
        }

玩家类:

public partial class Player
{
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
    public Player()
    {
        this.Bet = new HashSet<Bet>();
        this.PlayerLeague = new HashSet<PlayerLeague>();
    }

    public int PID { get; set; }
    public string NickName { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string BettingSite { get; set; }
    public Nullable<double> Balance { get; set; }

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<Bet> Bet { get; set; }
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<PlayerLeague> PlayerLeague { get; set; }

}

联赛班级:

public partial class League
{
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
    public League()
    {
        this.Bet = new HashSet<Bet>();
        this.PlayerLeague = new HashSet<PlayerLeague>();
    }

    public int LID { get; set; }
    public string Name { get; set; }
    public Nullable<System.DateTime> StartDate { get; set; }
    public Nullable<System.DateTime> EndDate { get; set; }
    public string Path { get; set; }

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<Bet> Bet { get; set; }
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<PlayerLeague> PlayerLeague { get; set; }

}

PlayerLeague:

public partial class PlayerLeague
{
    public int PLID { get; set; }
    public int PID { get; set; }
    public int LID { get; set; }

    public virtual League League { get; set; }
    public virtual Player Player { get; set; }
}

它以某种方式工作,但它创建了重复的条目,我不能这样做两次或删除一个条目。

我希望你能帮助我!

编辑:

这不会添加多个条目:

using (BettingLeagueEntities entities = new BettingLeagueEntities())
        {

            foreach (PlayerCheckBoxList p in this.PlayerList)
            {
                if(p.IsSelected == true)
                {
                    PlayerLeague pl = new PlayerLeague();
                    pl.League = this.ActiveLeague;
                    pl.Player = p.ActivePlayer;                    

                    entities.Entry(p.ActivePlayer).State = System.Data.Entity.EntityState.Modified;
                    entities.Entry(this.ActiveLeague).State = System.Data.Entity.EntityState.Modified;

                    p.ActivePlayer.PlayerLeague.Add(pl);
                    this.ActiveLeague.PlayerLeague.Add(pl);
                }

            }
            entities.SaveChanges();
        }
                    p.ActivePlayer.PlayerLeague.Add(pl);
                    this.ActiveLeague.PlayerLeague.Add(pl);
                }

            }

但我得到了这个例外:

  

附加信息:附加类型的实体   'BettingLeague.Model.PlayerLeague'失败,因为另一个实体   相同类型已具有相同的主键值。这可能发生   使用“附加”方法或将实体的状态设置为时   如果图中的任何实体具有“未更改”或“已修改”   冲突的关键值。这可能是因为一些实体是新的和   尚未收到数据库生成的键值。在这种情况下使用   “添加”方法或“已添加”实体状态可跟踪图表和   然后将非新实体的状态设置为“未更改”或“已修改”为   合适的。

1 个答案:

答案 0 :(得分:1)

如果将第一个代码块替换为仅分配ID的代码块,是否会产生重复?

            using (BettingLeagueEntities entities = new BettingLeagueEntities())
            {
                foreach (PlayerCheckBoxList p in this.PlayerList)
                {
                    PlayerLeague pl = new PlayerLeague();
                    pl.LID = ActiveLeague.ID;
                    pl.PID = p.ActivePlayer.ID;
                    entities.PlayerLeague.Add(pl);
                }                
                string saveString = ApplicationHelper.Save(entities);
                 // the saveString would make its way to 
                 //    the front-end to be show to the user.
            }

更新以显示如何查看导致DbUpdateException的原因。 (应该在您的工具箱中的代码。)

public class ApplicationHelper
{
      public static string Save(DbContext db)
        {
            StringBuilder sb = new StringBuilder();
            try
            {
                sb.Append(db.SaveChanges().ToString() + " changed");
            }
            catch (DbEntityValidationException ex)
            {
                foreach (var eve in ex.EntityValidationErrors)
                {
                    sb.AppendFormat(@"Entity of type '{0}' in state '{1}' has the following validation errors:",
                        eve.Entry.Entity.GetType().Name, eve.Entry.State);
                    sb.AppendLine();
                    foreach (var ve in eve.ValidationErrors)
                    {
                        sb.AppendFormat("- Property: '{0}', Error: '{1}'",
                            ve.PropertyName, ve.ErrorMessage);
                    }
                }

                sb.Append("ERROR: " + sb.ToString());
            }
            catch (DbUpdateException ex)
            {
                var de = TryDecodeDbUpdateException(ex);
                if (de == null)
                    throw;

                foreach (var e in de)
                    sb.AppendLine(e.MemberNames + " : " + e.ErrorMessage);

                sb.Append("ERROR: " + sb.ToString());
            }
            catch (Exception ex)
            {
                sb.Append("ERROR: " + (ex.InnerException == null ? ex.Message : ex.InnerException.Message));
            }
            return sb.ToString();
        }


        static IEnumerable<ValidationResult> TryDecodeDbUpdateException(DbUpdateException ex)
        {
            if (!(ex.InnerException is System.Data.Entity.Core.UpdateException) ||
                !(ex.InnerException.InnerException is System.Data.SqlClient.SqlException))
                return null;
            var sqlException =
                (System.Data.SqlClient.SqlException)ex.InnerException.InnerException;
            var result = new List<ValidationResult>();
            for (int i = 0; i < sqlException.Errors.Count; i++)
            {
                var errorNum = sqlException.Errors[i].Number;
                string errorText;
                if (_sqlErrorTextDict.TryGetValue(errorNum, out errorText))
                    result.Add(new ValidationResult(errorText));
            }
            return result.Any() ? result : null;
            }

      private static readonly Dictionary<int, string> _sqlErrorTextDict =
    new Dictionary<int, string>
{
    {547,
     "This operation failed because another data entry uses this entry."},
    {2601,
     "One of the properties is marked as Unique index and there is already an entry with that value."}
};
    }