2

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:

  • RoomManager.FillDeck(CurrentUser.CurrentRoom);
  • CurrentUser.CurrentRoom.SendCardsToPlayers(db);
  • db.Cards.RemoveRange(CurrentUser.CurrentRoom.CardsDeck.ToList());

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?

Dorki
  • 1,021
  • 2
  • 8
  • 23
  • You're loading the entity. While you load it, something is changing the value in the db. You can't update the loaded entity if the value changes while it's loaded in memory like that. – Train Aug 30 '19 at 21:54
  • @Train So what should I do in that case? – Dorki Aug 30 '19 at 22:07
  • 1
    Honestly my brain has turned to mush for the day. call Save after every transaction and remove them one by one to see where it's comming form. You might be deleting the cards, then trying to updated a deleted card that was in memory. – Train Aug 30 '19 at 22:12
  • @Train I'll try it! would be glad if you could also join the chat: https://chat.stackoverflow.com/rooms/7/c – Dorki Aug 30 '19 at 22:19
  • Update: So I made db.SaveChanges() after every change in the database, and I noticed that I receive the error after this line: CurrentUser.CurrentRoom.SendCardsToPlayers(); I updated the topic to see the code of this method. – Dorki Aug 30 '19 at 22:43
  • Can provide error after this line CurrentUser.CurrentRoom.SendCardsToPlayers();? – Cuppyzh Aug 31 '19 at 02:58
  • @Cuppyzh I removed this whole line, and it's not related to this line apparently, but the whole ICollection – Dorki Aug 31 '19 at 11:01
  • The problem might be because of a concurrency thing? – Dorki Aug 31 '19 at 11:13
  • What does `RoomManager.FillDeck(CurrentUser.CurrentRoom)` return? I'd like to see what the list values of `CardsDeck` is. – Train Sep 01 '19 at 01:20
  • @Train Yeah of course, I edited the topic to include the method FillDeck – Dorki Sep 01 '19 at 13:57
  • Btw, come to https://chat.stackoverflow.com/rooms/7/c if you can. – Dorki Sep 01 '19 at 13:59
  • Another update: I now getting this error after doing: db.Cards.RemoveRange(CurrentUser.CurrentRoom.CardsDeck); – Dorki Sep 01 '19 at 14:41
  • @Dorki I am drawing a blank on this question. Way too many unknown variables here for me to be able to jump into the middle of this. – Nkosi Sep 01 '19 at 16:04
  • @Nkosi what additional information should I provide? what methods/variables or maybe even code logic is needed? – Dorki Sep 01 '19 at 16:11

2 Answers2

1

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.

Train
  • 3,420
  • 2
  • 29
  • 59
1

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.

Dorki
  • 1,021
  • 2
  • 8
  • 23