Search Unity

iBoxDB -Lightweight Embedded Database

Discussion in 'Assets and Asset Store' started by Bruce3D, Dec 13, 2013.

  1. oziriz

    oziriz

    Joined:
    Jul 4, 2012
    Posts:
    7
    Hello! I have been trying some solutions for db WSA universal 8.1/10 and thought this could be it :). I am getting "Reference rewriter" errors and framework targeting issues. Is this normal because there it is not currently supported for the mentioned platforms or is there something wrong with my current setup? Thanks in advance for the help!

    Ed
     
  2. Bruce3D

    Bruce3D

    Joined:
    Sep 6, 2013
    Posts:
    54
    Hi, the universal solution has some info, but the output projects running fine. or use WP8+PC to build 2 projects.

    Updated:
    use IL2CPP or use iBoxDB.dll with WSDatabaseConfig.cs to replace the iBoxDB.NET.dll before build win8.1 app.

    http://www.iboxdb.com/
     
    Last edited: Sep 1, 2017
  3. Virdari

    Virdari

    Joined:
    Aug 19, 2014
    Posts:
    14
    Looks interesting, but I think you need to add further documentation as to how to use your db for someone who is completely new to databases like me. I will give it a try and explore it but I've got two questions:
    1- How is encryption handled ? Can someone get the data stored in the db by using something like cheat engine ?
    2- How can I use this to for instance to update the local database from a server? ( Do changes to the remote server db, and then push these changes to all the local databases on the device through an update maybe)
     
  4. Bruce3D

    Bruce3D

    Joined:
    Sep 6, 2013
    Posts:
    54
    1. use your own algorithm to encrypt important data.
    obj.amount = encrypt(value); value = decrypt(obj.amount);
    2. use MasterSlave Replication feature, place Master on servers and Slave on local devices.
    details in iBoxDB.cs- iBoxDB.Example.MasterSlave
     
  5. taecg

    taecg

    Joined:
    Jun 14, 2014
    Posts:
    26
    Very much like the database, but also in a lot of projects in the use of.
    Now there are a few small problems would like to ask the next:
    1. is there a GUI management tool for it?
    2. I now data is written to the database with the code, what is the good way to read EXCEL? The best is like the first one can have a GUI tool to manage.
    3. related API do not know where to look - - -!
     
  6. Bruce3D

    Bruce3D

    Joined:
    Sep 6, 2013
    Posts:
    54
    use 3rd-party components to read the data that generated by 3rd GUI (Excel or others) and put the data in a List<Dictionary<string,object>> list .
    then insert list into the database
    Code (CSharp):
    1. server.GetConfig().EnsureTable(tableName, list[0] , KeyColumnName );
    2. server.GetConfig().DBConfig.FileIncSize = 1;
    3. auto = server.Open();
    4. foreach (var obj in list) {
    5.     if (!auto.Replace(tableName, obj)) {
    6.         Console.WriteLine(columnName + obj[KeyColumnName] );
    7.    }
    8. }  
     
  7. donov

    donov

    Joined:
    Apr 15, 2013
    Posts:
    45
    Is this project still alive? asset store link?

    Wondering if to commit using it..
     
  8. Bruce3D

    Bruce3D

    Joined:
    Sep 6, 2013
    Posts:
    54
    Download from http://www.iboxdb.com/ , copy iBoxDB.NET2.dll to project.

    Btw, good question at April 1st, data don't die, enjoy it.
     
  9. donov

    donov

    Joined:
    Apr 15, 2013
    Posts:
    45
    Cool.
    Is there any other Docs on setting it up and using it in unity?
    Also how does it compare to siaqodb for unity or Couchbase for Unity, feature and performance wise?
     
  10. Bruce3D

    Bruce3D

    Joined:
    Sep 6, 2013
    Posts:
    54
    Setting up iBoxDB is easy, only copy iBoxDB.NET2.dll to the project for all platforms, haven't tried others, the Docs scared me.
     
  11. jaisiero

    jaisiero

    Joined:
    Jan 17, 2016
    Posts:
    1
    Excuse me, sir.

    Could you give me an example to make an entity relation one-many with Master -> Slave[ ] ?

    I must say your project is f****** awesome.

    Regards.
     
  12. Bruce3D

    Bruce3D

    Joined:
    Sep 6, 2013
    Posts:
    54
    Thanks.

    Code (CSharp):
    1. using System.Collections.Generic;
    2. using iBoxDB.LocalServer;
    3. using iBoxDB.LocalServer.Replication;
    4.  
    5.  
    6. public class Chocolate
    7. {
    8.     public long ID;
    9.     public string Type;
    10. }
    11. public class Ingredient
    12. {
    13.     public long ID;
    14.     public string Name;
    15.     //Chocolate
    16.     public long CID;
    17. }
    18.  
    19.  
    20. public class MainClass
    21. {
    22.     public static void Main(WriteDelegate Write)
    23.     {
    24.         DB db = new DB(7);
    25.         db.SetBoxRecycler(new Storehouse());
    26.         var config = db.GetConfig();
    27.         config.EnsureTable<Chocolate>("Chocolate", "ID");
    28.         config.EnsureTable<Ingredient>("Ingredient", "ID");
    29.         config.EnsureIndex<Ingredient>("Ingredient", "CID");
    30.  
    31.         AutoBox auto = db.Open();
    32.  
    33.         using (var box = auto.Cube())
    34.         {
    35.             Chocolate chocolate = new Chocolate();
    36.             chocolate.ID = box.NewId();
    37.             chocolate.Type = "Milk Chocolate";
    38.             box["Chocolate"].Insert(chocolate);
    39.  
    40.             Ingredient ingredient1 = new Ingredient();
    41.             ingredient1.ID = box.NewId();
    42.             ingredient1.Name = "Sugar";
    43.             ingredient1.CID = chocolate.ID;
    44.             box["Ingredient"].Insert(ingredient1);
    45.  
    46.             Ingredient ingredient2 = new Ingredient();
    47.             ingredient2.ID = box.NewId();
    48.             ingredient2.Name = "Whole milk powder";
    49.             ingredient2.CID = chocolate.ID;
    50.             box["Ingredient"].Insert(ingredient2);
    51.  
    52.             Ingredient ingredient3 = new Ingredient();
    53.             ingredient3.ID = box.NewId();
    54.             ingredient3.Name = "Cocoa butter";
    55.             ingredient3.CID = chocolate.ID;
    56.             box["Ingredient"].Insert(ingredient3);
    57.  
    58.             box.Commit().Assert();
    59.         }
    60.        
    61.         using (var box = auto.Cube())
    62.         {
    63.             Chocolate chocolate = new Chocolate();
    64.             chocolate.ID = box.NewId();
    65.             chocolate.Type = "Homemade Chocolate";
    66.             box["Chocolate"].Insert(chocolate);
    67.  
    68.             Ingredient ingredient1 = new Ingredient();
    69.             ingredient1.ID = box.NewId();
    70.             ingredient1.Name = "Sugar";
    71.             ingredient1.CID = chocolate.ID;
    72.             box["Ingredient"].Insert(ingredient1);
    73.  
    74.             Ingredient ingredient2 = new Ingredient();
    75.             ingredient2.ID = box.NewId();
    76.             ingredient2.Name = "Cocoa mass";
    77.             ingredient2.CID = chocolate.ID;
    78.             box["Ingredient"].Insert(ingredient2);
    79.  
    80.             box.Commit().Assert();
    81.         }
    82.  
    83.         Write("Master ");
    84.         using (var box = auto.Cube())
    85.         {
    86.             Print(Write, box);
    87.         }
    88.         //Slave[]
    89.         AutoBox s_auto7 = new DB(-7).Open();
    90.         AutoBox s_auto8 = new DB(-8).Open();
    91.  
    92.         var c = ((Storehouse)auto.GetDatabase().GetBoxRecycler()).ShipTo(s_auto7.GetDatabase(), s_auto8.GetDatabase());
    93.         ((Storehouse)auto.GetDatabase().GetBoxRecycler()).Remove(c);
    94.  
    95.         Write("Slave ");
    96.         using (var box = s_auto7.Cube())
    97.         {
    98.             Print(Write, box);
    99.         }
    100.  
    101.         Write("Slave ");
    102.         using (var box = s_auto8.Cube())
    103.         {
    104.             Print(Write, box);
    105.         }
    106.  
    107.         auto.GetDatabase().Dispose();
    108.         s_auto7.GetDatabase().Dispose();
    109.         s_auto8.GetDatabase().Dispose();
    110.     }
    111.  
    112.     public delegate void WriteDelegate(string str);
    113.  
    114.     private static void Print(WriteDelegate write, IBox box)
    115.     {
    116.         write(box.LocalAddress + "\r\n");
    117.         foreach (var c in box.Select<Chocolate>("from Chocolate"))
    118.         {
    119.             write("Chocolate: " + c.ID + "-" + c.Type + "\r\n");
    120.             foreach (var i in box.Select<Ingredient>("from Ingredient where CID==?", c.ID))
    121.             {
    122.                 write("  Ingredient: " + i.ID + "-" + i.Name + "\r\n");
    123.             }
    124.         }
    125.     }
    126. }
    127.  
    128. public class Storehouse : IBoxRecycler
    129. {
    130.     private List<byte[]> memoryStore = new List<byte[]>();
    131.     public void OnReceived(Socket socket, BoxData outBox, bool normal)
    132.     {
    133.         lock (memoryStore)
    134.         {
    135.             memoryStore.Add(outBox.ToBytes());
    136.         }
    137.     }
    138.  
    139.     public int ShipTo(params IDatabase[] slaves)
    140.     {
    141.         byte[][] cargoes = null;
    142.         lock (memoryStore)
    143.         {
    144.             cargoes = memoryStore.ToArray();
    145.         }
    146.         List<BoxData> listcargoes = new List<BoxData>();
    147.         foreach (byte[] cargo in cargoes)
    148.         {
    149.             listcargoes.Add(new BoxData(cargo));
    150.         }
    151.         if (listcargoes.Count > 0)
    152.         {
    153.             foreach (IDatabase idb in slaves)
    154.             {
    155.                 BoxData.SlaveReplicate(idb, listcargoes.ToArray());
    156.             }
    157.         }
    158.         return listcargoes.Count;
    159.     }
    160.  
    161.     public void Remove(int count)
    162.     {
    163.         lock (memoryStore)
    164.         {
    165.             memoryStore.RemoveRange(0, count);
    166.         }
    167.     }
    168.     public void Dispose()
    169.     {
    170.  
    171.     }
    172. }
     
  13. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    2,012
    I'm building a database for a friend and I use iBox. Love it, still I have a few questions.
    1. How would I do a search: typing "poi" returns all ID which have poi in the NAME?
    2. Select returns a collection, how do I select only one "from Client where ID ==" ID being unique
    3. In your examples I see new DB(7), why 7? Could you embed inline help in the dll?
    EDIT:
    1.
    Code (CSharp):
    1. foreach (var c in (from o in box.Select<Client>("from Client")
    2.                          where o.name.ToLower().Contains(s.ToLower())
    3.                          select o))
    2. append the linq method .First() at the end of the Select query
     
    Last edited: Apr 25, 2016
  14. Bruce3D

    Bruce3D

    Joined:
    Sep 6, 2013
    Posts:
    54
    3. Not a logical reason, just 7 in the middle of notebook keyboard.:cool:
     
  15. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    2,012
    And what does 7 stand for?
     
  16. Bruce3D

    Bruce3D

    Joined:
    Sep 6, 2013
    Posts:
    54
    Like an ID of the DB.
     
  17. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    2,012
    Gotcha!
    Why is this causing problems?
    Code (CSharp):
    1. Session session = box.Select<Session>("from Session where SID ==?", selectedID).First();
    2.  
    error: "
    InvalidOperationException: Operation is not valid due to the current state of the object
    System.Linq.Enumerable.First[Session] (IEnumerable`1 source)"

    Session has two keys: one that's unique SID and another one that I'm linking to another table (Session is multiple -> Client is one) called Client, both are defined as such:
    Code (CSharp):
    1. config.EnsureTable<Client>("Client", "ID");
    2. config.EnsureTable<Sessions.Session>("Session", "SID");
    I cannot verify what is written to the database but I know that when I add a new session it increments SID. By the way, is there a boxDB ready, in the same way there is a sqlite reader?
     
  18. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    2,012
    Tons more questions :)
    1. How do I delete the content of a table?
    2. What does this do exactly? config.EnsureTable<Client>("Client", "ID"); does that make ID the index and the key (same thing uh?) and makes lookup on ID unique and super fast?
    3. Does the index or the key need to be numeric and unique or can I index by name?
    4. am kind of shooting in the dark here but
      Code (CSharp):
      1. foreach (var s in box.Select<Session> ("from Session where ID == ? order by date, SID", Clients.selectedID)) {
      2.  
      This should find all entries in table "Session" that have matching ID to Clients.selectedID right? Doesn't. Any idea?
    5. I'm reading the .box file, it's gigantic, any pro tips to read the content?
    6. How do I reverse order?
      Code (CSharp):
      1. "from Session order by reverse date, SID"
      doesn't reverse date, I tried with DESC as well, no effect
    7. which brings me to this: What are the SQL keywords supported by iBox?
    EDIT: fixed the thing: this line kicked my ass because I left it to "Client" copy paste usually messes with your head
    Code (CSharp):
    1. box ["Client"].Insert (session);
    reversing order works by using Reverse()
     
    Last edited: Apr 25, 2016
  19. Bruce3D

    Bruce3D

    Joined:
    Sep 6, 2013
    Posts:
    54
    1. Seems change box ["Client"].Insert (session); to box ["Session"].Insert (session); can fix all questions.
    2. "Order by", try change "from Session order by reverse date, SID" to "from Session order by date desc, SID" or "order by date desc, SID desc"
     
    laurentlavigne likes this.
  20. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    2,012
    Thanks!
    Still the question about index and lower case sorting
    Also, with two tables, is it possible to generate a NewID() that's unique to each one?
    Currently if I add an entry to one table, it increments from the max (last index of each table)
     
  21. Bruce3D

    Bruce3D

    Joined:
    Sep 6, 2013
    Posts:
    54
    Index: supports String-ID,
    Lower case sorting: using Linq
    Tables ID: table1.ID= box.NewId(1,1); table2.ID= box.NewId(2,1);
     
    laurentlavigne likes this.
  22. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    2,012
    Awesome! Thanks again!
    I see in your web page mention of auto increment key, how do I set keys to be like this?
    Is it possible to add a bit more doc inline from a dll? I think they get nuked.
    An alternative would be to name the variable something like groupThatShareIDPool ;)
     
    Last edited: Apr 25, 2016
  23. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    2,012
    One more thing™ when the app launches it takes quite a while to startup, I'm thinking it's the database init, maybe it's loading entirely in memory. Is there a way to speed up init?
     
    Bruce3D likes this.
  24. Bruce3D

    Bruce3D

    Joined:
    Sep 6, 2013
    Posts:
    54
    write some test code to check the speed.
    begin()
    var db =...
    db.open()..
    end()
    printTime();
     
  25. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    2,012
    Is there a way to have box store one file per record?
    (got to make the applet multi user, each one working on one record... and they use dropbox to synch)
     
  26. Bruce3D

    Bruce3D

    Joined:
    Sep 6, 2013
    Posts:
    54
    Use Master-Master Replication
    Code (CSharp):
    1. public class FileStorehouse : IBoxRecycler
    2. {
    3.     public void OnReceived(Socket socket, BoxData outBox, bool normal)
    4.     {
    5.          WriteToNewFile( outBox.ToBytes() , .... );
    6.     }
    7. }
    8.  
    9. FileService.Sync();
    10.  
    11. new BoxData( ReadFromNewFiles() ).MasterReplicate( database );
    PS: OS has MAX_FILE_SIZE setting, you need to combine old files to big one file, or delete them.
     
  27. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    2,012
    I don't understand how any of it works. What's the part which replaces one file write with one file per table write? What does OnReceive, IBoxRecycler etc... do? Use of MasterReplicate?
     
  28. v0kb0l0k

    v0kb0l0k

    Joined:
    Feb 21, 2013
    Posts:
    9
    Hello, Bruce! In 5.3.1p2 with Mono2x Scripting Backend
    I have ios cross compiller error:

    Cross compilation job iBoxDB.NET2.dll failed.
    UnityEngine.UnityException: Failed AOT cross compiler: C:/Program Files/Unity/Editor/Data/PlaybackEngines/iOSSupport\Tools/Win/mono-xcompiler.exe --aot=full,asmonly,nodebug,nimt-trampolines=1024,nrgctx-trampolines=2048,ntrampolines=4096,static,outfile="iBoxDB.NET2.dll.s" "iBoxDB.NET2.dll" current dir : ...\Temp/StagingArea/Data/Managed
    result file exists: False. Timed out: False

    stdout:

    stderr:


    at UnityEditor.MonoProcessUtility.RunMonoProcess (System.Diagnostics.Process process, System.String name, System.String resultingFile) [0x000df] in C:\buildslave\unity\build\Editor\Mono\BuildPipeline\MonoAssemblyStripping.cs:113
    at UnityEditor.MonoCrossCompile.CrossCompileAOT (BuildTarget target, System.String crossCompilerAbsolutePath, System.String assembliesAbsoluteDirectory, CrossCompileOptions crossCompileOptions, System.String input, System.String output, System.String additionalOptions) [0x0033c] in C:\buildslave\unity\build\Editor\Mono\BuildPipeline\MonoCrossCompile.cs:318
    at UnityEditor.MonoCrossCompile+JobCompileAOT.ThreadPoolCallback (System.Object threadContext) [0x00000] in C:\buildslave\unity\build\Editor\Mono\BuildPipeline\MonoCrossCompile.cs:52
    UnityEditor.HostView:OnGUI()
     
    Last edited: May 17, 2016
  29. Bruce3D

    Bruce3D

    Joined:
    Sep 6, 2013
    Posts:
    54
    1. Set Strippling Level to "Strip Assemblies" or "Strip Byte Code"
    2. or Switch to "IL2CPP" backend
     
  30. housse

    housse

    Joined:
    May 21, 2016
    Posts:
    1
    Im planning to build a java base app, and considering to use iboxdb for database, so im trying to test the java version the other day and i get this error (javaFX using eclipse in ubuntu) :

    my code :
    public void onClick(){
    try {

    DB.root("/home/housse/Documents/Database/");
    DB server = new DB(1);
    server.getConfig().ensureTable(Disease.class, "Table", "ID");

    } catch(Exception e) {
    e.printStackTrace();
    }
    }

    the error :
    java.lang.RuntimeException: DB:CannotFoundField 'ID'
    at iBoxDB.bytecodes.b.a(SourceFile:26)
    at iBoxDB.bytecodes.a.a(SourceFile:80)
    at iBoxDB.bytecodes.ba.b(SourceFile:210)
    at iBoxDB.bytecodes.ba.a(SourceFile:35)
    at iBoxDB.LocalServer.DatabaseConfig.EnsureTable(SourceFile:69)
    at iBoxDB.LocalServer.DatabaseConfig$Config.ensureTable(SourceFile:145)
    at application.view.MainMenuController.onClick(MainMenuController.java:121)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at sun.reflect.misc.Trampoline.invoke(MethodUtil.java:71)
    at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at sun.reflect.misc.MethodUtil.invoke(MethodUtil.java:275)
    at javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1771)
    at javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1657)
    at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
    at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
    at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
    at javafx.event.Event.fireEvent(Event.java:198)
    at javafx.scene.Node.fireEvent(Node.java:8411)
    at javafx.scene.control.Button.fire(Button.java:185)
    at com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:182)
    at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:96)
    at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:89)
    at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
    at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
    at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
    at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
    at javafx.event.Event.fireEvent(Event.java:198)
    at javafx.scene.Scene$MouseHandler.process(Scene.java:3757)
    at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3485)
    at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762)
    at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2494)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:380)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:294)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$354(GlassViewEventHandler.java:416)
    at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:415)
    at com.sun.glass.ui.View.handleMouseEvent(View.java:555)
    at com.sun.glass.ui.View.notifyMouse(View.java:937)
    at com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
    at com.sun.glass.ui.gtk.GtkApplication.lambda$null$49(GtkApplication.java:139)
    at java.lang.Thread.run(Thread.java:745)


    So :
    1. is JavaFX or ubuntu a problem ?
    2. any idea what causes this ?
     
  31. Bruce3D

    Bruce3D

    Joined:
    Sep 6, 2013
    Posts:
    54
    Add an ID field to the class Disease.

    try this
    Code (CSharp):
    1.  
    2. import javafx.application.Application;
    3. import javafx.event.ActionEvent;
    4. import javafx.event.EventHandler;
    5. import javafx.scene.Scene;
    6. import javafx.scene.control.Button;
    7. import javafx.scene.layout.StackPane;
    8. import javafx.stage.Stage;
    9. import iBoxDB.LocalServer.*;
    10.  
    11. public class Jtest extends Application {
    12.  
    13.     static AutoBox auto;
    14.  
    15.     public static void main(String[] args) {
    16.         DB.root("/tmp/");
    17.         System.out.println("Begin");
    18.         DB db = new DB(1);
    19.         db.getConfig().ensureTable(Disease.class, "Disease", "ID");
    20.         auto = db.open();
    21.         launch(args);
    22.         auto.getDatabase().close();
    23.         System.out.println("End.");
    24.     }
    25.  
    26.     @Override
    27.     public void start(Stage primaryStage) {
    28.         primaryStage.setTitle("Hello Diseases!");
    29.         Button btn = new Button();
    30.         btn.setText("Say 'Hello Diseases'");
    31.  
    32.         btn.setOnAction(new EventHandler<ActionEvent>() {
    33.  
    34.             @Override
    35.             public void handle(ActionEvent event) {
    36.                 long curId = auto.newId();
    37.                 Disease ds = new Disease();
    38.                 ds.ID = curId;
    39.                 ds.Name = "NO." + ds.ID;
    40.                 auto.insert("Disease", ds);
    41.                 String msg = "Hello Disease "
    42.                         + auto.get(Disease.class, "Disease", curId).Name;
    43.                 btn.setText(msg);
    44.             }
    45.         });
    46.  
    47.         StackPane root = new StackPane();
    48.         root.getChildren().add(btn);
    49.         primaryStage.setScene(new Scene(root, 300, 250));
    50.         primaryStage.show();
    51.     }
    52.  
    53.     public static class Disease {
    54.  
    55.         public long ID; //the ID field
    56.         public String Name;
    57.     }
    58.  
    59. }
    60.  
     
  32. IsaacP

    IsaacP

    Joined:
    Nov 18, 2014
    Posts:
    3
    Hi, does this library handle inheritance?

    I would like to do something like this:

    Code (csharp):
    1.  
    2. auto.Insert("Table", new Member { ID = key, Name = "Bob"});
    3. auto.Insert("Table", new MemberVIP { ID = key+1, Name = "AndyVp", VIP = 3 });
    4. var o1 = auto.Get<Member>("Table", key+1);
    5. var o3 = o1 as MemberVIP;
    6.  
    ... I suppose I could always add type info with the data...

    Also are you planning on releasing the source? it would be easier to figure stuff out if I could look at the implementation.
     
    Last edited: Jun 10, 2016
  33. IsaacP

    IsaacP

    Joined:
    Nov 18, 2014
    Posts:
    3
    Also, I can't really find any examples for conflicts and I'm trying to figure out their exact meanings.

    Code (CSharp):
    1. public static CommitResult Conflict;
    2. public static CommitResult Duplicate;
    3. public static CommitResult IndexConstraint;
    Conflict -> is it property type mismatch (like the property 'quantity' is a number but in the Cube (iBox/Context) its a string? or maybe two objects have the same id but different types?

    Duplicate -> You created an object in the iBox and created an object in the AutoBox with the same id?

    Index Constraint -> the id of the new object is out of bounds? (if that was the case shouldn't it fail on insert? unless the id's bounds can be changed...)

    Also, is there anyway for me to pull more detail about the error.. What if I wanted to implement behavior so it would 'override' or 'discard' the existing data if there is a conflict?

    Thanks for your time! (seriously consider open source and I won't bug you ;P)
     
  34. Bruce3D

    Bruce3D

    Joined:
    Sep 6, 2013
    Posts:
    54
    1. Use database's index to get correct Class directly, that is fast and low memory.
    2. Conflict -> Two threads write same object, the second will return Conflict
    3. Example

    Code (CSharp):
    1.     public class Member
    2.     {
    3.         public long ID;
    4.         public String Name;
    5.         public override string ToString()
    6.         {
    7.             return "NotVIP " + " " + Name + "  ID=" + ID;
    8.         }
    9.     }
    10.  
    11.     public class MemberVIP : Member
    12.     {
    13.         public int VIP;
    14.  
    15.         public override string ToString()
    16.         {
    17.             return "VIP=" + VIP + " " + Name + " ID=" + ID;
    18.         }
    19.     }
    20.  
    21.  
    22.  
    23.     void Start()
    24.     {
    25.         DB.Root(Application.persistentDataPath);
    26.  
    27.         DB db = new DB(8);
    28.         db.GetConfig().EnsureTable<Member>("Table", "ID");
    29.         //db.GetConfig().EnsureIndex<MemberVIP>("Table", "VIP");
    30.  
    31.         var auto = db.Open();
    32.         long key = auto.NewId(0, 2);// 2 means 2-IDs, with key+1
    33.         auto.Insert("Table", new Member { ID = key, Name = "Bob" });
    34.         auto.Insert("Table", new MemberVIP { ID = key + 1, Name = "AndyVp", VIP = 3 });
    35.  
    36.         // 2 ways to deal with Class
    37.         // 1. use VIP property to read the correct Class directly.
    38.         Debug.Log("Way 1");
    39.         MemberVIP mv = auto.Select<MemberVIP>("from Table where ID==? & VIP>=?", key + 1, 0).FirstOrDefault(); // ID before VIP
    40.         Debug.Log(mv.ToString());
    41.         // "as MemberVIP" is not necessary, because always NULL      
    42.         mv = auto.Select<MemberVIP>("from Table where ID==? & VIP>=?", key, 0).FirstOrDefault();
    43.         Debug.Log("NotVIP " + mv);
    44.  
    45.  
    46.         //2. use ContainsKey() instead of AS
    47.         Debug.Log("Way 2");
    48.  
    49.         foreach (var local in auto.Select("from Table where ID>=?", key))
    50.         {
    51.             if (local.ContainsKey("VIP"))
    52.             {
    53.              //convert Entity to object
    54.                 MemberVIP lmv = local.Entity.Select<MemberVIP>();
    55.                 Debug.Log(lmv.ToString());
    56.             }
    57.             else
    58.             {
    59.                 Member lm = local.Entity.Select<Member>();
    60.                 Debug.Log(lm.ToString());
    61.             }
    62.         }
    63.  
    64.         //Conflict -> records don't have problem, just two Boxes collided
    65.         var box1 = auto.Cube();
    66.         var box2 = auto.Cube();
    67.  
    68.         Member bob1 = box1["Table", key].Select<Member>();
    69.         bob1.Name += " Box1";
    70.         box1["Table"].Update(bob1);
    71.  
    72.  
    73.         Member bob2 = box2["Table", key].Select<Member>();
    74.         bob2.Name += " Box2";
    75.         box2["Table"].Update(bob2);
    76.  
    77.         //OK
    78.         box1.Commit().Assert();
    79.  
    80.         //Conflict
    81.         var cr = box2.Commit();
    82.         Debug.Log(cr + " :" + cr.GetErrorMsg(box2));
    83.         Debug.Log("Updated: " + auto.Get("Table", key));
    84.  
    85.  
    86.         //Duplicate -> records hava problem, mostly the same id
    87.         //IndexConstraint ->  EnsureTable/Index<>("Table", "Name(32)"), mostly the string.length definition (32), it is modifiable.
    88.  
    89.  
    90.         auto.GetDatabase().Dispose();
    91.  
    92.     }
     
    Last edited: Jul 24, 2017
    IsaacP likes this.
  35. Duc-Huy

    Duc-Huy

    Joined:
    May 31, 2015
    Posts:
    2
    Thank you for a great DB, but I have a couple questions. I have a prepopulated box DB from another application and now I want my Game will loaded it first, but it seem that Unity3D not support for copy these .box and .box.swp to Application.persistentDataPath so I think I will have to load it from byte array inside Resources folder. here my code
    Code (CSharp):
    1. void initDB()
    2. {
    3.     if (db == null)
    4.     {
    5.         DB.Root(Application.persistentDataPath);
    6.         Debug.Log(string.Format("Load data at {0}", Application.persistentDataPath));
    7.         var dataBytes = Resources.Load<TextAsset>("Database/db1.box.swp").bytes;
    8.  
    9.  
    10.         server = new DB(dataBytes);
    11.         server.GetConfig().EnsureTable<Word>("Words", "word");
    12.         db = server.Open();
    13.         var c = db.SelectCount("from Words");
    14.         Debug.Log(string.Format("Total word {0}", c));
    15.     }
    16. }
    17.    
    And I got these error
    I check it in Unity3d Editor and wonder if we have another solution for prepopulated database ?
     
  36. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    2,012
    I've been detangling some old spaghetti code and realize that I'd love a database to handle all my entities. Has anyone done so with Box?
     
  37. Bruce3D

    Bruce3D

    Joined:
    Sep 6, 2013
    Posts:
    54
    Hello,
    The ".swp" file is a temporary backup file, the ".box" is the database file.
    1. Change db1.box => db1.bytes, delete "*.box.*".
    2. Load from bytes, db = new DB(((TextAsset)(UnityEngine.Resources.Load("db1"))).bytes);
    https://docs.unity3d.com/Manual/class-TextAsset.html

    Another solution: using streamingAssetsPath.
    https://forum.unity3d.com/threads/iboxdb-lightweight-embedded-database.217097/#post-2259001

    Code (CSharp):
    1. db = new DB(dataBytes);
    2. // EnsureTable() not necessary.
    3. //db.GetConfig().EnsureTable<Word>("Words", "word");
    4. var auto = db.Open();
    5. var c = auto.SelectCount("from Words");
    6. Debug.Log(string.Format("Total word {0}", c));

    http://www.iboxdb.com/
     
    Last edited: Feb 13, 2017
  38. ehsan1234

    ehsan1234

    Joined:
    Aug 5, 2015
    Posts:
    2
    Hi, does this library support database password?
    can any1 post an example?
    sry for my noobi question, first time try using database...
     
  39. Bruce3D

    Bruce3D

    Joined:
    Sep 6, 2013
    Posts:
    54
    Hello,
    doesn't support password, have to write an IO layer by yourself. example:
    https://github.com/iboxdb/aspnet-cross-platform-db/blob/master/IO/EncryptDatabaseConfig.cs

    faster way is encode data before save it.
    MyClass mc = new..
    mc.field1 = encode( "ABCD" );
    return decode(mc.field1);

    or
    Code (CSharp):
    1. class MyClass2{
    2.    public byte[]  _field1;
    3.  
    4.    [NotColumn]
    5.    public String Field1{
    6.       set{  _field1 = encode(value); }
    7.       get{ return decode(_field1); }
    8.    }
    9. }
     
  40. KNorbt

    KNorbt

    Joined:
    Jul 26, 2016
    Posts:
    2
    Hi,

    I appreciate your hard work on this project. I've just found iBoxDB and I'm already in love with it.
    Can I store nested objests? I have a class like this:

    Code (CSharp):
    1. class MyClass {
    2.     public long ID;
    3.     public string name;
    4.     public List <AnotherClass> list;
    5. }
    6.  
    7. class AnotherClass {
    8.     public long ID;
    9.     public int something;
    10. }
    Can you show me, how can I store MyClass?
     
  41. Bruce3D

    Bruce3D

    Joined:
    Sep 6, 2013
    Posts:
    54
    Hello,
    only support flat objects, use ID to make connections between objects. iBoxDB has transaction, objects can work together with flexible way, nested objects not important.

    Code (CSharp):
    1. class MyClass {
    2.     public long ID;
    3.     public string name;
    4.     public IEnumerable<AnotherClass> GetAnotherClass( box ){
    5.    return box.Select( "from AnotherClass where MID=?", this.ID);
    6. }
    7. }
    8. class AnotherClass {
    9.     public long ID;
    10.     public int something;
    11.     public long MID;
    12. }
    13.  
    14. Config.EnsureTable<AnotherClass>("AnotherClass", "ID");
    15. Config.EnsureIndex<AnotherClass>("AnotherClass", "MID");
     
  42. KNorbt

    KNorbt

    Joined:
    Jul 26, 2016
    Posts:
    2
    Hi again!

    First of all:
    Thank you for the database engine. It is free, it is stable, it is fast and I don't have to worry about saving and loading data to and from the disk any more. I can use my model classes as-is. I can fetch my objects easier. No cons, only pros. I've been using it happily for the last two weeks.

    And here is my question:
    Does EnsureTable ensures indexes?
    Code (CSharp):
    1. Config.EnsureTable<MyClass>("Table", "ID", "MID", "type");
    or
    Code (CSharp):
    1. Config.EnsureTable<MyClass>("Table", "ID");
    2. Config.EnsureIndex<MyClass>("Table", ["MID", "type"]);
     
  43. Bruce3D

    Bruce3D

    Joined:
    Sep 6, 2013
    Posts:
    54
    Hello,
    call EnsureTable() one time to create one table. only for table.
    call EnsureIndex() one time to create one index.

    one Key(of database) consists of three fields(of class MyClass)
    Code (CSharp):
    1. //One Key(Database) with three Fields(of C# Class)
    2. Config.EnsureTable<MyClass>("Table", "ID", "MID", "type")
    3. auto.Get<MyClass>( "Table",  A, B, C);
    4.  
    5.  
    6. //One Key with One Field
    7. Config.EnsureTable<MyClass>("Table", "ID")
    8. auto.Get<MyClass>( "Table",  A);
    the Key of Table also be used as Index when it works better.
     
  44. iddqd

    iddqd

    Joined:
    Apr 14, 2012
    Posts:
    386
    Great project! Many thanks for it!
     
  45. Bruce3D

    Bruce3D

    Joined:
    Sep 6, 2013
    Posts:
    54
    Your projects are great too!
     
    iddqd likes this.
  46. iddqd

    iddqd

    Joined:
    Apr 14, 2012
    Posts:
    386
    If i have an array "string[] values" - Is there a way to compare a field against this array (like "where in")?
    Something like auto.SelectCount("from MyData where Field in ?", values);

    Of should is use linq for this?

    Thanks!
     
  47. Bruce3D

    Bruce3D

    Joined:
    Sep 6, 2013
    Posts:
    54

    If the Field is a String, not String[], add an Index, and use foreach to do it
    Code (CSharp):
    1. config.EnsureIndex<MM>( "MM" , "Field" );
    2.  
    3. count = 0;
    4. using (var box = auto.Cube ()) {
    5.    foreach (string tag in searchTags) {
    6.       count += box.SelectCount ("from MM where Field == ?", tag);
    7.    }
    8. }
     
    Last edited: Aug 26, 2017
  48. Bruce3D

    Bruce3D

    Joined:
    Sep 6, 2013
    Posts:
    54
    Updated:
    If the Field is a String[], the answer depends on how big the data you have, and how many records do you want to get.
    faster way is using KeyOnly table to make an Index for String[],
    the following is my test result, 1,000,000 objects with 3,000,000 tags. (when objects less than 10,000, the results are very close)

    Search [Tag1,Tag4]
    IndexSearch Count: 666,667 , Seconds 0.6723593
    FullSearch Count: 666,667 , Seconds 2.0626479

    Update Tags Update Tags [Tag3,Tag4,Empty2] to [NEW1,NEW2]
    Search [Tag1,Tag4]
    IndexSearch Count: 666,666 , Seconds 0.6407091
    FullSearch Count: 666,666 , Seconds 2.5467883

    Search [NEW1]
    IndexSearch Count: 1 , Seconds 0 // here is Zero, not copy error.
    FullSearch Count: 1 , Seconds 2.5467605

    Code (CSharp):
    1.         public class MM
    2.         {
    3.             public long ID;
    4.             public String[] Tags;
    5.  
    6.             public static bool Insert (IBox box, MM value)
    7.             {
    8.                 if (value.Tags != null) {
    9.                     foreach (String tag in value.Tags) {
    10.                         box ["/MMR"].Insert (new MMRelation (){ Tag = tag, ID = value.ID });
    11.                     }
    12.                 }
    13.                 return box ["MM"].Insert (value).Has ();
    14.             }
    15.  
    16.             public static bool Update (IBox box, MM newValue)
    17.             {
    18.                 MM oldValue = box ["MM", newValue.ID].Select <MM> ();
    19.            
    20.                 if (!newValue.Tags.SequenceEqual (oldValue.Tags)) {
    21.                     if (oldValue.Tags != null) {
    22.                         foreach (String tag in oldValue.Tags) {
    23.                             box ["/MMR", tag, oldValue.ID].Delete ();
    24.                         }
    25.                     }
    26.                     if (newValue.Tags != null) {
    27.                         foreach (String tag in newValue.Tags) {
    28.                             box ["/MMR"].Insert (new MMRelation (){ Tag = tag, ID = newValue.ID });
    29.                         }
    30.                     }
    31.                 }
    32.  
    33.                 return box ["MM", newValue.ID].Update (newValue).Has ();
    34.             }
    35.         }
    36.  
    37.         public class MMRelation
    38.         {
    39.             public string Tag;
    40.             public long ID;
    41.  
    42.             public MM Select (IBox box)
    43.             {
    44.                 return box ["MM", ID].Select<MM> ();
    45.             }
    46.         }
    47.  
    48.         public static IEnumerable<MMRelation> IndexSearch (IBox box, string[] searchTags)
    49.         {
    50.             var hs = new HashSet<long> ();
    51.  
    52.             foreach (string tag in searchTags) {
    53.                 foreach (MMRelation mr in box.Select<MMRelation> ("from /MMR where Tag == ?", tag)) {
    54.                     if (hs.Add (mr.ID)) {
    55.                         yield return mr;
    56.                     }
    57.                 }
    58.             }
    59.         }
    60.  
    61.         public static IEnumerable<MM> FullSearch (IBox box, string[] searchTags)
    62.         {
    63.             foreach (var mm in box.Select<MM>("from MM")) {
    64.                 string[] tags = mm.Tags;
    65.                 if (tags != null) {
    66.                     foreach (string tag in tags) {
    67.                         foreach (string stag in searchTags) {
    68.                             if (tag == stag) {
    69.                                 yield return mm;
    70.                                 goto Found;
    71.                             }
    72.                         }
    73.                     }
    74.                 }
    75.                 Found:
    76.                 continue;
    77.             }
    78.         }
    79.  
    80.         public static void Main (string[] args)
    81.         {
    82.             iBoxDB.LocalServer.DB.Root (@"c:\temp\db");
    83.             iBoxDB.DBDebug.DDebug.DeleteDBFiles (1L);
    84.             DB db = new DB (1L);
    85.             var cfg = db.GetConfig ();
    86.             cfg.EnsureTable<MM> ("MM", "ID");
    87.             //KeyOnly Table stores relations, Tag first for WHERE
    88.             cfg.EnsureTable<MMRelation> ("/MMR", "Tag", "ID");
    89.  
    90.             cfg.DBConfig.CacheLength = cfg.DBConfig.MB (800);
    91.             cfg.DBConfig.SwapFileBuffer = (int)cfg.DBConfig.MB (1);
    92.  
    93.             AutoBox auto = db.Open ();
    94.            
    95.             int time = 10000;
    96.             int batch = 100;
    97.             Console.WriteLine ("Inserting...");
    98.             // 1,000,000 objects with 3,000,000 tags
    99.             DBPlatform.For (0, time, (i) => {
    100.                 using (var box = auto.Cube ()) {
    101.                     for (int id = i * batch; id < (i + 1) * batch; id++) {
    102.                         MM mm = new MM (){ ID = id };
    103.                         switch (id % 3) {
    104.                         case 0:
    105.                             mm.Tags = new string[]{ "Tag1", "Tag2", "Empty0" };
    106.                             break;
    107.                         case 1:
    108.                             mm.Tags = new string[]{ "Tag2", "Tag3", "Empty1" };
    109.                             break;
    110.                         default:
    111.                             mm.Tags = new string[]{ "Tag3", "Tag4", "Empty2" };
    112.                             break;
    113.                         }
    114.                         MM.Insert (box, mm);
    115.                     }
    116.                     box.Commit ().Assert ();
    117.                 }
    118.             });
    119.             Console.WriteLine ("Begin Search...");
    120.  
    121.  
    122.             for (int f = 0; f < 3; f++) {
    123.                 string[] searchTags = new string[]{ "Tag1", "Tag4" };
    124.                 if (f == 2) {
    125.                     searchTags = new string[]{ "NEW1" };
    126.                 }
    127.                 Console.WriteLine ("");  
    128.                 Console.WriteLine ("Search " + DB.ToString (searchTags));
    129.                 long count = 0;
    130.                 Console.Write ("IndexSearch");
    131.                 DDebug.StartWatch ();
    132.                 count = 0;
    133.                 using (var box = auto.Cube ()) {
    134.                     foreach (var mr in IndexSearch(box,searchTags)) {
    135.                         count++;
    136.                     }
    137.                 }
    138.                 Console.Write ("  Count: " + count.ToString ("#,#"));
    139.                 Console.WriteLine (" , Seconds " + DDebug.StopWatch ().TotalSeconds);
    140.  
    141.                 Console.Write ("FullSearch ");
    142.                 DDebug.StartWatch ();
    143.                 count = 0;
    144.                 using (var box = auto.Cube ()) {
    145.                     foreach (var mr in FullSearch(box,searchTags)) {
    146.                         count++;
    147.                     }
    148.                 }
    149.                 Console.Write ("  Count: " + count.ToString ("#,#"));
    150.                 Console.WriteLine (" , Seconds " + DDebug.StopWatch ().TotalSeconds);
    151.                    
    152.                 if (f == 0) {
    153.                     Console.WriteLine ("");
    154.                     Console.Write ("Update Tags ");
    155.                     using (var box = auto.Cube ()) {
    156.                         long id = time / 2 * batch;
    157.                         MM re = box ["MM", id].Select<MM> ();
    158.                         Console.Write ("Update Tags " + DB.ToString (re.Tags) + " to ");
    159.                         re.Tags = new string[] { "NEW1", "NEW2" };
    160.                         Console.Write (DB.ToString (re.Tags));
    161.                         MM.Update (box, re);
    162.                         box.Commit ().Assert ();
    163.                     }
    164.                 }
    165.             }
    166.         }
    167.  
    168.  
    169.         public class DBPlatform
    170.         {
    171.             public delegate void FRun (int i);
    172.  
    173.             #if  NET2
    174.             public static void For(int start, int end, FRun run)
    175.             {
    176.             for (var i = start; i < end; i++)
    177.             {
    178.             run(i);
    179.             }
    180.             }
    181. #else
    182.             public static void For (int start, int end, FRun run)
    183.             {
    184.                 System.Threading.Tasks.Parallel.For (start, end,
    185.                     (i) => {
    186.                         run (i);
    187.                     });
    188.             }
    189.             #endif
    190.         }
    191.  
     
    iddqd likes this.
  49. Duc-Huy

    Duc-Huy

    Joined:
    May 31, 2015
    Posts:
    2
    Hi Bruce
    Is there any way to drop table in iBoxDB without delete and create new file ?
     
  50. Bruce3D

    Bruce3D

    Joined:
    Sep 6, 2013
    Posts:
    54
    Data are important, Ignore the Table as it is transparent.
     
    Duc-Huy likes this.