Dorki
Dorki

Reputation: 1207

ASP.NET db.savechange System.Data.Entity.Infrastructure.DbUpdateException

So, I got a weird situation,

I get this error message:

System.Data.Entity.Infrastructure.DbUpdateException: 'An error occurred while saving entities that do not expose foreign key properties for their relationships. The EntityEntries property will return null because a single entity cannot be identified as the source of the exception. Handling of exceptions while saving can be made easier by exposing foreign key properties in your entity types. See the InnerException for details.'

InnerException:

OptimisticConcurrencyException: Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=472540 for information on understanding and handling optimistic concurrency exceptions.

I'm trying to build a card-game using AJAX and .NET,

Now, the thing is I have a Method1 that requires to make some changes in a Room entity, this is the full code of the method:

   public string OpenCards()
    {
        IsLogged = (System.Web.HttpContext.Current.User != null) && System.Web.HttpContext.Current.User.Identity.IsAuthenticated;
        if (IsLogged)
            CurrentUser = db.Users.Find(User.Identity.GetUserId());
        else
            return "NotLoggedIn";

        if (CurrentUser.CurrentRoom == null)
            return "UserNotConnectedToRoom";

        if (CurrentUser.CurrentRoom.Round == 0)
        {
            CurrentUser.CurrentRoom.SetAllPlayingThisRound(true);

            // DELETE THE PREVIOUS CurrentUser.CurrentRoom.CardsDeck
            CurrentUser.CurrentRoom.RemovePlayersCards(db); 
            if(CurrentUser.CurrentRoom.CardsDeck != null) 
            {
                db.Cards.RemoveRange(CurrentUser.CurrentRoom.CardsDeck);
            }

            List<Card> list = RoomManager.FillDeck(CurrentUser.CurrentRoom);
            CurrentUser.CurrentRoom.CardsDeck = list;

            CurrentUser.CurrentRoom.SendCardsToPlayers();
            db.SaveChanges(); // ERROR HAPPENS HERE


            return "....";


        }

        return "";
    }

I get the message error while doing: db.SaveChanges()

So basically, from this code what matters to know is that I'm changing three entities: ApplicationUser, Room and Cards.

Now, every few seconds, Method2 is being called, and what it does is basically displaying some data from the db context.

Now from what I've read on the internet, this error occur from two reasons:

  1. As it says from the error itself: something related to Nulls.
  2. Something related to concurrency.

Now the weird thing is, this error doesn't happen all the time, and I can't reproduce it, nor knowing the reason why it happens.

So before trying to fix it, how would I know whether the reason for this error is 1. or 2.? what should I looking for in the debugging mode?

Edit:

My Models:

public class Card
{
    public int CardId { get; set; }
    public int Value { get; set; }
    public string Type { get; set; }
}

public class Room
{
    public int RoomId { get; set; }
    public string Name { get; set; }
    public int EnterPrice { get; set; }
    public int UserDecisionTime { get; set; }
    public virtual ICollection<Card> CardsDeck { get; set; }
    public virtual ICollection<Card> CardsOnTable { get; set; }
    public int WhosTurnChairIndex { get; set; }
    public virtual ApplicationUser Chair0 { get; set; }
    public virtual ApplicationUser Chair1 { get; set; }
    public virtual ApplicationUser Chair2 { get; set; }
    public virtual ApplicationUser Chair3 { get; set; }
    public virtual ApplicationUser Chair4 { get; set; }
    public int FirstRound { get; set; }
    public int Round { get; set; }
}

And some Data of cards from the SQL Server:

enter image description here

enter image description here

Edit: After @Train 's suggestion to make db.SaveChanges() after every line of changing the database, I noticed that I receive an error after this line:

CurrentUser.CurrentRoom.SendCardsToPlayers();

So this is the method:

    public void SendCardsToPlayers()
    {
        for (int i = 0; i < 5; i++)
        {
            ApplicationUser user = (ApplicationUser)GetProperty(this, "Chair" + i);

            if (user != null && user.IsPlayingThisRound == true && IsPlayerHasEnoughMoney(user))
            {
                Card c1 = CardsDeck.First();
                CardsDeck.Remove(c1);

                Card c2 = CardsDeck.First();
                CardsDeck.Remove(c2);

                user.CardOne = c1;
                user.CardTwo = c2;
            }
            else if (user != null)
            {
                user.IsPlayingThisRound = false;
            }
        }
    } 

This method is placed in Room's entity.

ANOTHER NOTE: I tried to remove the lines: CardsDeck.Remove(c1); and CardsDeck.Remove(c2);

but it's still make this error.

So the problem is at: Card c1 = CardsDeck.First();

maybe because I don't make from CardsDeck.ToList(), it makes problems?

Edit: As request, FillDeck's method:

    public static List<Card> FillDeck(Room room)
    {
        List<Card> list = new List<Card>();
        string[] names = new string[]
        {
            "Club", "Diamond", "Heart", "Spade"
        };

        // Creating the Card deck

        for(int i = 0; i < 13; i++)
        {
            for(int j = 0; j < 4; j++)
            {
                list.Add(new Card
                {
                    Value = i,
                    Type = names[j]
                });
            }
        }

        list.Shuffle();
        return list;
    }

** Another Note: ** I found out that if I delete everything related to Cards, which are:

it works with no problem, is the problem might be caused because of Card entity? Another solution I thought about is to make Card as a string ( split with commas ) or even JSON inside the string, so it might solve the whole Cards issue?

Upvotes: 2

Views: 872

Answers (2)

Dorki
Dorki

Reputation: 1207

So I managed to solve the problem, instead of using Card, I just used a string property and made a split using comma, a full example can be found here:

Entity Framework - Code First - Can't Store List<String>

Tho, it means that I really had an issue with Card, since it could be owned by many Entities: Room, ApplicationUser it probably caused some issues with null foreign key.

Upvotes: 1

Train
Train

Reputation: 3496

It's kind of hard to tell what's going on with the code you have some methods missing. Here is what I think the problem is.

Your Card Entity has the properties

{
     CardID: ... //Primary Key
     value: ...
     Type: ...
     CurrentRoom... //is this a foreign Key?
     ...//other properties
}

But when you create it you only have 2 properties.

           list.Add(new Card
            {
                Value = i,
                Type = names[j] 
            }); //no foriegn key or primary key defined

You can't do DB operations with an incomplete entity. You haven't defined the Primary and foreign keys for the cards and then when you do all your db operations, it doesn't know which cards to do the crud operations on.

Upvotes: 1

Related Questions