I'm writing a game server to which many players connect. I load up the DB into a DataSet(strong typed). Every time a player logs in, I add a new row to Messages table using a TableAdapter.
code
var newRow = _db.Messages.NewMessagesRow(); // _db is a strong-typed-dataset
{
newRow.Title = title;
newRow.Text = text;
newRow.ReceiverUID = receiverUID;
newRow.Deleted = false;
}
// I lock the _db.Messages, so it happens one at a time
lock ( _db.Messages )
{
_db.Messages.AddMessagesRow( newRow );
_adapterMessages.Connection.Open();
_adapterMessages.Update( newRow );
newRow.MessageID = (Int64)_adapterMessages.GetIdentity();
newRow.AcceptChanges();
_adapterMessages.Connection.Close();
}
NewMessagesRow() and AddMessagesRow() is auto-generated by VS. I did it by adding a DataSet item(.xsd file) and dragging all the DB tables to it.
public MessagesRow NewMessagesRow() {
return ((MessagesRow)(this.NewRow()));
}
public void AddMessagesRow(MessagesRow row) {
this.Rows.Add(row);
}
_db is a DataSet(strong-typed, auto-generated by VS) _db.Messages is a DataTable.
while in testing, I get
System.Data.NoNullAllowedException: Column 'Deleted' does not allow nulls.
at System.Data.DataColumn.CheckNullable(DataRow row)
at System.Data.DataTable.RaiseRowChanging(...)
at System.Data.DataTable.SetNewRec开发者_开发知识库ordWorker(...)
at System.Data.DataTable.InsertRow(...)
at System.Data.DataRowCollection.Add(DataRow row)
at Server.Database.MessagesDataTable.AddMessagesRow(MessagesRow row)
AddMessagesRow() gets called only in the code above, and I always set false for Deleted column, but still gets this message...
I don't use _adapterMessages anywhere else, but there are other adapters (_adapterUsers, _adapterMatches,... etc) that could be used concurrently.
I don't get the exception every time, but if the server runs for sometime(like > 30 min) with about 1000 concurrent players, it happens.
Any help or advices will be greatly appreciated. Thanks :)
I figured out the root cause of this problem. I thought DataTable.NewRow() was thread-safe, but it's not. I have to lock exclusively before I call NewRow() on any tables.
so the code above needs to be changed like:
lock ( _db.Messages )
{
var newRow = _db.Messages.NewMessagesRow();
{
newRow.Title = title;
newRow.Text = text;
newRow.ReceiverUID = receiverUID;
newRow.Deleted = false;
}
_db.Messages.AddMessagesRow( newRow );
_adapterMessages.Connection.Open();
_adapterMessages.Update( newRow );
newRow.MessageID = (Int64)_adapterMessages.GetIdentity();
newRow.AcceptChanges();
_adapterMessages.Connection.Close();
}
You can refer to google search results on this issue..
精彩评论