I'm trying to run a transaction with realtime database to change an object, with the following code :
void tryBeHost()
{
string path = "weeks/" + week + "/games/" + gameId + "/gameInfo";
_dbRef.Child(path).RunTransaction(mutableData =>
{
GameInfo gameInfo = mutableData.Value as GameInfo;
if (gameInfo == null)
{
gameInfo = new GameInfo();
}
else if (gameInfo.host != null && gameInfo.host != myId)
{
return TransactionResult.Success(mutableData);
}
gameInfo.host = myId;
mutableData.Value = gameInfo;
return TransactionResult.Success(mutableData);
});
}
so I'm getting this weird error :
Exception in transaction delegate, aborting transaction
Firebase.Database.DatabaseException: Failed to parse object Serializables.GameInfo ---> System.ArgumentException: Invalid type Serializables.GameInfo for conversion to Variant
at Firebase.Variant.FromObject (System.Object o) [0x001df] in Z:\tmp\tmp.EaS8iXpRBh\firebase\app\client\unity\proxy\Variant.cs:117
at Firebase.Database.Internal.Utilities.MakeVariant (System.Object value) [0x00000] in Z:\tmp\tmp.sZ8vrpcx53\firebase\database\client\unity\proxy\Utilities.cs:25
--- End of inner exception stack trace ---
at Firebase.Database.Internal.Utilities.MakeVariant (System.Object value) [0x0000d] in Z:\tmp\tmp.sZ8vrpcx53\firebase\database\client\unity\proxy\Utilities.cs:27
at Firebase.Database.MutableData.set_Value (System.Object value) [0x00000] in Z:\tmp\tmp.sZ8vrpcx53\firebase\database\client\unity\proxy\MutableData.cs:136
at InternetShit.b__10_0 (Firebase.Database.MutableData mutableData) [0x00045] in /Users/sandukhan/Unity/projects/Ronda/Assets/Scripts/InternetShit.cs:73
at Firebase.Database.Internal.InternalTransactionHandler.DoTransaction (System.Int32 callbackId, System.IntPtr mutableData) [0x00022] in
Z:\tmp\tmp.sZ8vrpcx53\firebase\database\client\unity\proxy\InternalTransactionHandler.cs:49
UnityEngine.Debug:LogWarning(Object)
Firebase.Platform.FirebaseLogger:LogMessage(PlatformLogLevel, String) (at Z:/tmp/tmp.BbQyA8B710/firebase/app/client/unity/src/Unity/FirebaseLogger.cs:92)
Firebase.LogUtil:LogMessage(LogLevel, String) (at Z:/tmp/tmp.EaS8iXpRBh/firebase/app/client/unity/proxy/LogUtil.cs:68)
Firebase.Database.Internal.InternalTransactionHandler:DoTransaction(Int32, IntPtr) (at Z:/tmp/tmp.sZ8vrpcx53/firebase/database/client/unity/proxy/InternalTransactionHandler.cs:51)
Firebase.AppUtilPINVOKE:PollCallbacks()
Firebase.AppUtil:PollCallbacks() (at Z:/tmp/tmp.EaS8iXpRBh/firebase/app/client/unity/proxy/AppUtil.cs:32)
Firebase.Platform.FirebaseAppUtils:PollCallbacks() (at Z:/tmp/tmp.EaS8iXpRBh/firebase/app/client/unity/proxy/FirebaseAppUtils.cs:33)
Firebase.Platform.FirebaseHandler:Update() (at Z:/tmp/tmp.BbQyA8B710/firebase/app/client/unity/src/Unity/FirebaseHandler.cs:205)
Firebase.Platform.FirebaseMonoBehaviour:Update() (at Z:/tmp/tmp.BbQyA8B710/firebase/app/client/unity/src/Unity/FirebaseMonoBehaviour.cs:45)
my GameInfo Class is the following :
using System;
using Serializables;
namespace Serializables
{
[Serializable]
public class GameInfo
{
public string gameId;
public string host;
public string[] playersIds;
public string[] playersPics;
public string[] playersNames;
}
}
if anyone has an idea to solve this I will be grateful
I think you figured out the basics: You can only submit bool, string, long, double, IDictionary, and List<Object> to Value.
There's some interesting notes that I'd like to layer on top of this though! I like to use Unity's JsonUtility in conjunction with SetRawJsonValueAsync and GetRawJsonValue from GetValueAsync. Your code will look a bit like this:
async void SendGameInfo(string path, GameInfo info) {
try {
await _database
.GetReference(path)
.SetRawJsonValueAsync(JsonUtility.ToJson(info));
Debug.Log($"Successfully wrote {info}");
} catch (AggregateException e) {
Debug.LogWarning($"Failed with {e}");
}
}
async Task<GameInfo> ReadGameInfo(string path) {
try {
var dataSnapshot = await _database
.GetReference(path)
.GetValueAsync();
return JsonUtility.FromJson<GameInfo>(info);
} catch (AggregateException e) {
Debug.LogWarning($"Failed with {e}");
return null;
}
}
Also, if you can, having spent time digging through the library I like to consider IDictionary<string, object> the "basic primitive" of Realtime Database. This will be used as an intermediary format when you set RawJson if you step through the disassembly. Also, since Transactions don't provide access to raw json, this will give you a more uniform interface to RTDB (unless your data looks like an array, then your primitive is List<object> - "looks like" meaning that your keys are numbers and the range of numbers RTDB is aware of is about half full).
Of course, the team actively monitors the quickstart github page and you can use the new "feature request" template to request a change to any of this if it will help 😃.
I think RTFM always works, I found out that there are specific types that are accepted for mutableData.Value : bool, string, long, double, IDictionary and List{Object} where Object is one of previously listed types. So I got this error because my class GameInfo is not accepted and I have to convert my object to an IDictionary.
source : https://firebase.google.com/docs/reference/unity/class/firebase/database/mutable-data#class_firebase_1_1_database_1_1_mutable_data_1a4833f23246b3079078332d57c5649254
Related
i've a strange error in SQLite using a transaction, that i cannot figured out....
below there is my code:
_connection.RunInTransaction(() =>
{
_connection.UpdateAll(objProposte);
foreach (Proposte objProposta in objProposte)
{
string propostaID = objProposta.PropostaID;
List<ProposteDetails> lstProdDet = _connection.Table<ProposteDetails>().Where(x => x.PropostaID == propostaID).ToList();
if (lstProdDet != null && lstProdDet.Count() > 0)
{
//AN UPDATE GIVE ME THE SAME ERROR
_connection.DeleteAll(lstProdDet);
_connection.InsertAll(lstProdDet);
}
}
});
Seems that the _connection.UpdateAll(objProposte); works correctly, but when i try to do something else in the same transaction i got the following exception:
System.ArgumentException: savePoint is not valid, and should be the
result of a call to SaveTransactionPoint. Parameter name: savePoint
at SQLite.Net.SQLiteConnection.DoSavePointExecute (System.String
savePoint, System.String cmd) [0x00063] in
<8f2bb39aeff94a30a8628064be9c7efe>:0 at
SQLite.Net.SQLiteConnection.Release (System.String savepoint)
[0x00000] in <8f2bb39aeff94a30a8628064be9c7efe>:0 at
SQLite.Net.SQLiteConnection.RunInTransaction (System.Action action)
[0x0001d] in <8f2bb39aeff94a30a8628064be9c7efe>:0 at
SQLite.Net.SQLiteConnection.InsertAll (System.Collections.IEnumerable
objects, System.Boolean runInTransaction) [0x0001e] in
<8f2bb39aeff94a30a8628064be9c7efe>:0
Reading on the internet seems something related to a nested transaction, but is not my situation because is all done in the same transaction.
Thanks,
L-
edit 28-05-2018 12:16: That configuration works.... but should do the same things of the above :(
string my_transaction_point = null;
try
{
my_transaction_point = _connection.SaveTransactionPoint();
_connection.UpdateAll(objProposte, runInTransaction: false);
foreach (Proposte objProposta in objProposte)
{
string propostaID = objProposta.PropostaID;
List<ProposteDetails> lstProdDet = _connection.Table<ProposteDetails>().Where(x => x.PropostaID == propostaID).ToList();
if (lstProdDet != null && lstProdDet.Count() > 0)
{
_connection.DeleteAll(lstProdDet);
_connection.InsertAll(lstProdDet, runInTransaction: false);
}
}
_connection.Commit();
}
catch (Exception ex)
{
_connection.RollbackTo(my_transaction_point);
throw new Exception("UpdateProposta, " + ex.Message, ex);
}
.UpdateAll runs within its own transaction by default, you can turn that off by overriding the second parameter which defaults to true:
_connection.RunInTransaction(() =>
{
_connection.UpdateAll(objProposte, false);
// perform the rest of your CRUD operations
~~~
~~~
});
I've implemented a login manager in my game using Parse, and everything worked well.
So I've added an online leaderboard, but now each time Unity executes a method like this:
void UpdateOnlineScore(string id, int newScore)
{
var query = ParseObject.GetQuery("tableName").WhereEqualTo("userid", id);
query.FirstAsync().ContinueWith(t => {
if (t.IsFaulted)
{
Debug.LogWarning("ID not found");
// user stats not found create from scratch
}
else
{
Debug.Log("Record found");
ParseObject obj = t.Result;
int savedScore = (int) obj.Get<int>("score");
// check record
}
});
}
it stops at query.FirstAsync().ContinueWith(...) throwing this exception:
ArgumentException: Cannot include control characters in a HTTP header, either as key or value.
UnityEngine.WWW.CheckSecurityOnHeaders (System.String[] headers) (at C:/BuildAgent/work/d63dfc6385190b60/Runtime/Export/WWW.cs:98)
UnityEngine.WWW..ctor (System.String url, System.Byte[] postData, System.Collections.Generic.Dictionary`2 headers) (at C:/BuildAgent/work/d63dfc6385190b60/artifacts/EditorGenerated/Utils.cs:88)
Parse.PlatformHooks.GenerateWWWInstance (System.String uri, System.Byte[] bytes, System.Collections.Hashtable headerTable)
Parse.PlatformHooks+<>c__DisplayClass30+<>c__DisplayClass36.b__29 ()
Parse.PlatformHooks+d__3c.MoveNext ()
UnityEngine.Debug:LogException(Exception)
Parse.d__3c:MoveNext()
I have no idea what I'm doing wrong.
What's strange is that I get this error only debugging on Web Player platform.
On Windows Standalone it doesn't show up.
Am I missing something?
I'm usign Unity 4.6.0f3.
My Code is following :
try
{
MongoDatabase mtest1 = mongoServer.GetDatabase("ews", mC);
MongoCollection<EliteGuard> ecollection1 = mtest1.GetCollection<EliteGuard>("EliteGuard");
int intC = FindUser(comboBox1.Text.ToString());
int intCount = 0;
foreach (EliteGuard t in ecollection1.FindAll())
{
if (t.product_key.Equals(comboBox1.Text.ToString()))
{
intCount++;
}
}
if (intC <= intCount)
{
MessageBox.Show("Total no. of Serial Key is generated.", "Elite Manager Information", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
}
catch (MongoConnectionException mcex)
{
MessageBox.Show("Unable to connect to Server. Please try Again.", "Elite Manager Information", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
catch (Exception ex)
{
return;
}
Error :
An error occurred while deserializing the product_key property of
class Serial_Key_Generation.Form5+EliteGuard: Input string was not in
a correct format.
StackTrace : at
MongoDB.Bson.Serialization.BsonClassMapSerializer.DeserializeMember(BsonReader
bsonReader, Object obj, BsonMemberMap memberMap) at
MongoDB.Bson.Serialization.BsonClassMapSerializer.Deserialize(BsonReader
bsonReader, Type nominalType, Type actualType,
IBsonSerializationOptions options) at
MongoDB.Bson.Serialization.BsonClassMapSerializer.Deserialize(BsonReader
bsonReader, Type nominalType, IBsonSerializationOptions options) at
MongoDB.Bson.Serialization.BsonSerializer.Deserialize(BsonReader
bsonReader, Type nominalType, IBsonSerializationOptions options) at
MongoDB.Driver.Internal.MongoReplyMessage1.ReadFrom(BsonBuffer
buffer, IBsonSerializationOptions serializationOptions) at
MongoDB.Driver.Internal.MongoConnection.ReceiveMessage[TDocument](BsonBinaryReaderSettings
readerSettings, IBsonSerializationOptions serializationOptions) at
MongoDB.Driver.MongoCursorEnumerator1.GetReply(MongoConnection
connection, MongoRequestMessage message) at
MongoDB.Driver.MongoCursorEnumerator1.GetFirst() at
MongoDB.Driver.MongoCursorEnumerator1.MoveNext() at
Serial_Key_Generation.Form5.comboBox1_SelectedIndexChanged(Object
sender, EventArgs e) in D:\Projects\Serial Key Generation\Serial Key
Generation\Form5.cs:line 94
But the same type of code is working properly on another Form.
An error occurred while deserializing the product_key property of
class Serial_Key_Generation.Form5+EliteGuard: Input string was not in
a correct format.
There is an inconsistency between the implementation of the EliteGuard class and your database data. The product_key property in that class does not match its equivalent in the database. It's possible you defined it as the wrong data type in your class definition. It seems to be expecting a string but it's not getting one. You'll need to change the data type of product_key either in the class definition or in the DB (class definition is probably easier).
But the same type of code is working properly on another Form.
That doesn't really tell me much. Are you loading data from the same DB & collection and are you using the same class? It's hard to answer this without more information. In any case it sounds like something is different, because it's not having trouble deserializing there. Try stepping through the code in each scenario and see what is different from one form to the other. It may just be a small difference that you overlooked. Having a separate working example should make it easier to see what is wrong with the form that doesn't work.
Yes that is connecting same database and code is the same from another Form.
I'm developing in C#, and using Dotnetzip's Source code to get the application in one file.
But when running, i get the exception:
System.OverflowException: Arithmetic operation resulted in an overflow.
at Ionic.Crc.CRC32..ctor(Int32 polynomial, Boolean reverseBits) in DotNetZip\CRC32.cs:line 452
at Ionic.Crc.CRC32..ctor(Boolean reverseBits) in DotNetZip\CRC32.cs:line 418
at Ionic.Crc.CRC32..ctor() in DotNetZip\CRC32.cs:line 398
at Ionic.Crc.CrcCalculatorStream..ctor(Boolean leaveOpen, Int64 length, Stream stream, CRC32 crc32) in DotNetZip\CRC32.cs:line 622
at Ionic.Crc.CrcCalculatorStream..ctor(Stream stream) in DotNetZip\CRC32.cs:line 519
at Ionic.Zip.ZipEntry.ExtractOne(Stream output) in DotNetZip\ZipEntry.Extract.cs:line 1043
at Ionic.Zip.ZipEntry.InternalExtract(String baseDir, Stream outstream, String password) in DotNetZip\ZipEntry.Extract.cs:line 870
at Ionic.Zip.ZipEntry.Extract(String baseDirectory, ExtractExistingFileAction extractExistingFile) in DotNetZip\ZipEntry.Extract.cs:line 240
at ItxInstaller.Package.GetData(String instFilePath) in Package.cs:line 32
at ItxInstaller.Install..ctor() in Install.cs:line 26
at ItxInstaller.Program.Main(String[] args) in Program.cs:line 54
The Install.cs is like this:
public Install()
{
// The InitializeComponent() call is required for Windows Forms designer support.
this.InitializeComponent();
Package pack = Package.GetData(Program.args[1]);
this.Title.Text = pack.AppName;
this.PathBox.Text = pack.GeneratePath();
}
The Package.cs contains the GetData():
class Package
{
public string AppName;
public string ExePath;
private string FilePath;
public Package(string filePath)
{
this.ValueInit(filePath);
this.FilePath = filePath;
}
public static Package GetData(string instFilePath)
{
using (ZipFile Package = ZipFile.Read(instFilePath))
{
Package["app.itx"].Extract(Path.GetTempPath(), ExtractExistingFileAction.OverwriteSilently);
}
return new Package(Path.Combine(Path.GetTempPath(), "app.itx"));
}
}
How to solve this exception?
I can reproduce this problem with Mono when using "-checked+" as parameter, i.e. with enabled arithmetic checks. Omitting this parameter results in a working executable.
There is also a project setting for it in Visual Studio.
I've extracted the relevant code into this working program so you can test it yourself:
using System;
namespace Test {
public class Program {
public static void Main(string[] args) {
CRC32 test = new CRC32();
Console.Out.WriteLine(test.dwPolynomial);
}
}
public class CRC32 {
public UInt32 dwPolynomial;
public CRC32() : this(false) {
}
public CRC32(bool reverseBits) :
this(unchecked((int)0xEDB88320), reverseBits) {
}
public CRC32(int polynomial, bool reverseBits) {
this.dwPolynomial = (uint) polynomial; // this is line 452
}
}
}
Using dcms test.cs && mono test.exe runs fine.
Using dcms -checked+ test.cs && mono test.exe results in a
Unhandled Exception: System.OverflowException: Number overflow.
at Test.Program.Main (System.String[] args) [0x00000] in <filename unknown>:0
[ERROR] FATAL UNHANDLED EXCEPTION: System.OverflowException: Number overflow.
at Test.Program.Main (System.String[] args) [0x00000] in <filename unknown>:0
Update: if you can't or don't want to disable arithmetic checks then you could modify the source code of like 452 to
this.dwPolynomial = unchecked((uint) polynomial);
This turns off arithmetic checks for the expression.
I am trying to add a record to my database table using LINQ to SQL and ASP.NET MVC 2.
The snippet in my controller that populates the LINQ object is this:
/* other code removed */
if (ModelState.IsValid)
{
var stream = new Genesis.Domain.Entities.Stream();
// Handle stream
// Is this stream new?
if (form.StreamID == 0)
{
// create new stream
stream.StreamUrl = form.StreamUrl;
stream.StreamName = form.StreamName;
stream.StreamBody = form.StreamBody;
stream.StreamTitle = form.StreamTitle;
stream.StreamKeywords = form.StreamKeywords;
stream.StreamDescription = form.StreamDescription;
form.StreamID = genesisRepository.CreateStream(stream); // CreateStream() returns ID as long
}
/* other code removed */
The genesisRepository.CreateStream() looks like this:
public partial class SqlGenesisRepository : IGenesisRepository
{
public long CreateStream(Stream stream)
{
streamTable.InsertOnSubmit(stream);
streamTable.Context.SubmitChanges();
return stream.StreamID;
}
}
When genesisRepository.CreateStream() gets executed, I get this error:
Updated to more accurate error and stacktrace
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.NullReferenceException: Object reference not set to an instance of an object.
Source Error:
Line 13: public long CreateStream(Stream stream)
Line 14: {
Line 15: streamTable.InsertOnSubmit(stream);
Line 16: streamTable.Context.SubmitChanges();
Line 17: return stream.StreamID;
Source File: C:\path\to\SqlGenesisRepositoryStreamPartial.cs Line: 15
Stack Trace:
[NullReferenceException: Object reference not set to an instance of an object.]
System.Data.Linq.Mapping.EntitySetDefSourceAccessor`2.GetValue(T instance) +18
System.Data.Linq.Mapping.MetaAccessor`2.GetBoxedValue(Object instance) +47
System.Data.Linq.StandardTrackedObject.HasDeferredLoader(MetaDataMember deferredMember) +106
System.Data.Linq.StandardTrackedObject.get_HasDeferredLoaders() +107
System.Data.Linq.StandardChangeTracker.Track(MetaType mt, Object obj, Dictionary`2 visited, Boolean recurse, Int32 level) +175
System.Data.Linq.StandardChangeTracker.Track(Object obj, Boolean recurse) +83
System.Data.Linq.StandardChangeTracker.Track(Object obj) +12
System.Data.Linq.Table`1.InsertOnSubmit(TEntity entity) +183
Genesis.Domain.Concrete.SqlGenesisRepository.CreateStream(Stream stream) in C:\Documents and Settings\bquakkelaar\Desktop\dropstuff\asp.net mvc\Genesis.0.02\Genesis.Domain\Concrete\SqlGenesisRepositoryStreamPartial.cs:15
Genesis_0_02.Controllers.AdminStreamController.StreamEdit(StreamEditModel form) in C:\Documents and Settings\bquakkelaar\Desktop\dropstuff\asp.net mvc\Genesis.0.02\Genesis.0.02\Controllers\AdminStreamController.cs:107
lambda_method(Closure , ControllerBase , Object[] ) +108
System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters) +51
System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters) +409
System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters) +52
System.Web.Mvc.<>c__DisplayClassd.<InvokeActionMethodWithFilters>b__a() +127
When I put a breakpoint into the function, I see that stream is not null. Some strings are null. Required strings are not null (IE: streamName = "name") and StreamID is 0.
Where am I going wrong?
Edit: How `streamTable` is instanced
I don't think there is a problem with how I instance streamTable but seeing as how I out of ideas and most people here think that it's null, here is the code that instances streamTable.
public partial class SqlGenesisRepository : IGenesisRepository
{
private Table<Stream> streamTable;
public SqlGenesisRepository(string connectionString)
{
streamTable = (new DataContext(connectionString)).GetTable<Stream>();
}
public IQueryable<Stream> Streams { get { return streamTable; } }
}
And the SqlGenesisRepository is instanced in the controller class like this:
public class AdminStreamController : Controller
{
private IGenesisRepository genesisRepository;
public AdminStreamController()
{
//genesisRepository = new FakeGenesisRepository();
genesisRepository = new SqlGenesisRepository(ConfigurationManager.ConnectionStrings["genesis"].ConnectionString);
}
/* rest of code removed for brevity */
}
Thanks to everyone for the attention to this issue.
It looks like the incorrect code wasn't in any of the code I posted here. I rephrased my question and posted it here: Is there a secret to using LINQ to SQL to add records when the object has relationships?.
The solution can be found there!
Thanks again.
You don't need to attach the object to the table since the object is new. You just need to InsertOnSubmit.
If you get a null exception after removing that line, your Stream object is likely missing a required field.
Maybe streamTable is null?
Edit
Okay, so based on the stack trace I'm thinking that you may be missing a foreign key constraint. What relationships does a Stream have? Can you create a new Stream in your database using hand-coded SQL, given only the information that you have in this code?
Have you tried explicitly declaring Stream as Genesis.Domain.Entities.Stream ?
As in:
private Table<Genesis.Domain.Entities.Stream> streamTable;
public SqlGenesisRepository(string connectionString)
{
streamTable = (new DataContext(connectionString)).GetTable<Genesis.Domain.Entities.Stream>();
}
Because "Stream" alone could be confusing the compiler, as System.IO.Stream
Also, when you put a breakpoint at
streamTable.InsertOnSubmit(stream);
...to check if streamTable is null, did you check its contents with the debugger?
That part where it says "Expanding this item will enumerate ...".
It's important because generally it lazy loads, therefore it doesn't go to the DB unless it requires a transaction.