0

I have a series of methods that do some insertions into the database in a pretty set order. However, I'm running into an issue where one of the methods is firing off before the other method is called, unless I put a breakpoint in.

My initial thought was that due to me passing around IEnumerables, the method wasn't firing off until the Controller was returning the object, but after converting everything to lists, the error still occurs.

My code looks something like the following:

// controller
public IActionResult CreateConversation([FromBody] CreateConvoRequest model)
{
    var userId = ViewBag.UserData.UserID;

    model.message.UserFrom = userId;
    model.users.Add(userId);

    var result = MessagingLogic.CreateConversation(model.conversation, model.message, model.users);

    return Json(result);
}

// Logic
public static Conversation CreateConversation(Conversation conversation, ConversationMessage message,
    List<int> users)
{
    conversation.DateCreated = DateTime.Now;
    conversation.LastUpdated = DateTime.Now;

    var convo = SaveNewConversation(conversation, users);

    message.ConversationId = convo.ConversationId;
    SendMessage(message);

    return convo;
}

public static Conversation SaveNewConversation(Conversation conversation, List<int> users)
{
    conversation = SaveConversation(conversation);
    conversation.Users = users.Select(n => CreateConversationUser(conversation.ConversationId, n)).ToList();
    // the above linq executes some SQL insertions and returns the new object
    return conversation;
}

public static ConversationMessage SendMessage(ConversationMessage message)
{
    if (message.CloseConversation) CloseConversation(message.ConversationId);

    return SaveMessage(message);
}

What appears to be happening is that SendMessage is being called before CreateConversationUser. This is turn causes my messages not to be saved for the users as they aren't saved into the database until after the SendMessage method is called.

However, if I put a breakpoint on SaveNewConversation method, everything works as intended.


Edit

So after some more tinkering, adding the ToList to my Linq Selected corrected the issue with it executing out of order. However, my SendMessage SQL statement is using a INSERT INTO SELECT. It appears that the users often haven't been inserted into the database by the time the SendMessage sql executes.

For example, 2 of my users were inserted at 2017-09-20 10:29:35.820 and 2017-09-20 10:29:35.823 respectively. However, the message was inserted at 2017-09-20 10:29:35.810.

It appears something odd is happening on the SQL server.


Edit 2

Further testing is putting the entirety of the blame on SQL Server. I ran the SQL Profiler tool and the calls are coming in, in the correct order. However, there is only roughly a 3 millisecond delay between the last user being inserted and the messages being inserted.

If I place a sleep statement between the user insert and the message insert of a couple hundred milliseconds, it works as intended. I'm not quite sure how to address this issue, but it no longer appears to be executing out of order.

JD Davis
  • 3,517
  • 4
  • 28
  • 61
  • can u post the method that is calling SendMessage ? – Allanckw Sep 20 '17 at 15:02
  • It's listed above. `CreateConversation` calls `SendMessage` – JD Davis Sep 20 '17 at 15:03
  • "What appears to be happening is that SendMessage is being called before CreateConversationUser" what makes you say that other than placing the breakpoint? – BurnsBA Sep 20 '17 at 15:09
  • If I place a breakpoint on `SendMessage` and query the database table that the users should have been inserted in, they're missing. However, if I let it run to completion, they're present. I can also place a breakpoint inside the `CreateConversationUser` method in my repository, and it's being called after the `SendMessage` breakpoint triggered. – JD Davis Sep 20 '17 at 15:11
  • Are you reusing the same database connection for all these calls? What's `CreateConversationUser` look like? – BurnsBA Sep 20 '17 at 15:13
  • can u insert debug.print in all ur methods to see if the SendMessage is indeed executed before CreateConversation? Dun insert breakpoints since u are saying it is working with it enabled – Allanckw Sep 20 '17 at 15:13
  • This looks like an defered execution of the Select extension method. This is by design. I guess that the SendMessage method is the firs that accesses the Users property. Have a look here https://stackoverflow.com/questions/7324033/what-are-the-benefits-of-a-deferred-execution-in-linq – Rene Niediek Sep 20 '17 at 15:17
  • 4
    @Alander typing "you" instead of "u" isn't much effort, please do it as it makes your comments more readable. – stuartd Sep 20 '17 at 15:19
  • 1
    @ReneNiediek Not with the `ToList` tagged on the end - you will need to scroll right to see it. – DavidG Sep 20 '17 at 15:26
  • So oddly enough, if I throw debug print statements throughout all the methods, it appears to work 99.9% of the time. This leads me to believe that maybe there's some strange race condition happening at the database level. If I remove the debug print statements, it fails pretty consistently 99.9% of the time. – JD Davis Sep 20 '17 at 15:33
  • It appears to all be a strange race condition on the SQL server side. The commands all come in, in order, but they're only a couple milliseconds apart. I can either attempt to slow it down, or change my SQL Insert logic to no longer use INSERT INTO SELECT. – JD Davis Sep 20 '17 at 16:16
  • Are you using transactions in code? – BurnsBA Sep 20 '17 at 17:12
  • 1
    You really shouldn't be executing code with side effects using LINQ or especially LINQ `Select`. – NetMage Sep 20 '17 at 17:52
  • @BurnsBA No, there are no transactions. Each statement is fired off in sequence. – JD Davis Sep 20 '17 at 18:04

0 Answers0