0

First: I created a Data-First-Model!

i have a m-to-m relation. To handle this relation i added an entity between:

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

I want to update all PlayerLeagues (add/delete).

This is my code for this so far:

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();
        }

Player class:

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

}

League class:

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

It does somehow work, but it creates duplicate entries and i can't do this twice or delete an entry.

I hope you can help me!

Edit:

This does not add multiple entries:

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);
                }

            }

But i get this exception:

Additional information: Attaching an entity of type 'BettingLeague.Model.PlayerLeague' failed because another entity of the same type already has the same primary key value. This can happen when using the 'Attach' method or setting the state of an entity to 'Unchanged' or 'Modified' if any entities in the graph have conflicting key values. This may be because some entities are new and have not yet received database-generated key values. In this case use the 'Add' method or the 'Added' entity state to track the graph and then set the state of non-new entities to 'Unchanged' or 'Modified' as appropriate.

8
  • Please show how your entities are set up in code including the joining table. Commented Nov 28, 2015 at 14:42
  • allright i updated the question! Commented Nov 28, 2015 at 14:46
  • I don't think you should define the middle table explicitly, just use navigation properties to collection of player in the league, and collection of league in the player. You can define how they join in the model builder, see msdn.microsoft.com/en-us/data/jj591620.aspx#ManyToMany Commented Nov 28, 2015 at 14:52
  • I didn't do code first, so I guess your suggestion does not work for me Commented Nov 28, 2015 at 15:28
  • I think the problem is with SaveChanges. Can you move SaveChanges inside the for loop? Or keep the program in debug and check the table after first add and see if the record got inserted. Commented Nov 28, 2015 at 16:43

1 Answer 1

1

Does it make a duplicate if you replace your first code block with one that just assigns IDs?

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

Update to show how to see what caused a DbUpdateException. (Code that should be in your toolbox.)

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."}
};
    }
Sign up to request clarification or add additional context in comments.

3 Comments

No, it doesn't, but if I run it a second time, the following exception shows up: An unhandled exception of type 'System.Data.Entity.Infrastructure.DbUpdateException' occurred in EntityFramework.dll Do you have any suggestions to solve this?
@JBrooks - where is your "_sqlErrorTextDict" defined at?
@bitshift I added it to the bottom

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.