VelocityDB Sample Applications
Storing instances of class Person
Person.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using VelocityDb;
namespace VelocityDbSchema.Samples.Sample1
{
public class Person : OptimizedPersistable
{
string firstName;
string lastName;
UInt16 age;
public Person(string firstName, string lastName, UInt16 age)
{
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
}
}
}
Sample1.cs
using System;
using VelocityDb.Session;
using VelocityDbSchema.Samples.Sample1;
namespace Sample1
{
class Sample1
{
static readonly string systemDir = "Sample1"; // appended to SessionBase.BaseDatabasePath
static int Main(string[] args)
{
using (SessionNoServer session = new SessionNoServer(systemDir))
{
Console.WriteLine("Running with databases in directory: " + session.SystemDirectory);
session.BeginUpdate();
Person person = new Person("Robin", "Hood", 30);
session.Persist(person);
person = new Person("Bill", "Gates", 56);
session.Persist(person);
person = new Person("Steve", "Jobs", 56);
session.Persist(person);
session.Commit();
}
return 0;
}
}
}
Looking at the Person objects in the DatabaseManager
Adding a relation to class Person
Person.cs
using System;
using VelocityDb;
namespace VelocityDbSchema.Samples.Sample2
{
public class Person : OptimizedPersistable
{
string m_firstName;
string m_lastName;
UInt16 m_age;
Person m_bestFriend;
public Person(string firstName, string lastName, UInt16 age, Person bestFriend = null)
{
m_firstName = firstName;
m_lastName = lastName;
m_age = age;
m_bestFriend = bestFriend;
}
public Person BestFriend
{
get
{
return m_bestFriend;
}
set
{
Update();
m_bestFriend = value;
}
}
}
}
Sample2.cs
using VelocityDb.Session;
using VelocityDbSchema.Samples.Sample2;
namespace Sample2
{
class Sample2
{
static readonly string systemDir = "Sample2"; // appended to SessionBase.BaseDatabasePath
static void Main(string[] args)
{
using (SessionNoServer session = new SessionNoServer(systemDir))
{
session.BeginUpdate();
Person robinHood = new Person("Robin", "Hood", 30);
Person billGates = new Person("Bill", "Gates", 56, robinHood);
Person steveJobs = new Person("Steve", "Jobs", 56, billGates);
robinHood.BestFriend = billGates;
session.Persist(steveJobs); // the other persons will be persisted implicetly by reachability from "Steve Jobs" person object
session.Commit();
}
}
}
}
Looking at the Sample 2 Person objects through the DatabaseManager
Adding a VelocityDbList to class Person and using fuzzy string matching
When using VelocityDbList instreade of List, the list is assigned an Oid instead of
being directly embedded in the parent object. If a list is to be shared between
multiple objects then VelocityDbList should be used.
Person.cs
using System;
using VelocityDb;
using VelocityDb.Collection;
namespace VelocityDbSchema.Samples.Sample4
{
public class Person : OptimizedPersistable
{
string m_firstName;
string m_lastName;
UInt16 m_age;
Person m_bestFriend;
VelocityDbList<Person> m_friends;
public Person(string firstName, string lastName, UInt16 age, Person bestFriend = null)
{
m_firstName = firstName;
m_lastName = lastName;
m_age = age;
m_bestFriend = bestFriend;
m_friends = new VelocityDbList<Person>();
}
public Person BestFriend
{
get
{
return m_bestFriend;
}
set
{
Update();
m_bestFriend = value;
}
}
public string FirstName
{
get
{
return m_firstName;
}
set
{
Update();
m_firstName = value;
}
}
public VelocityDbList<Person> Friends
{
get
{
return m_friends;
}
}
}
}
Looking at the objects through the DatabaseManager
Main program of Sample4. It also shows how to unpersist (delete from database) objects and how to use fuzzy string matching
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using VelocityDb;
using VelocityDb.Session;
using VelocityDbSchema.Samples.Sample4;
using VelocityDb.Collection;
using System.IO;
using FuzzyString;
namespace Sample4
{
class Sample4
{
static readonly string s_systemDir = "Sample4"; // appended to SessionBase.BaseDatabasePath
static void Main(string[] args)
{
try
{
SessionBase.DefaultCompressPages = PageInfo.compressionKind.LZ4;
using (SessionNoServer session = new SessionNoServer(s_systemDir))
{
Console.WriteLine("Running with databases in directory: " + session.SystemDirectory);
session.BeginUpdate();
// delete (unpersist) all Person objects created in prior run
foreach (Person p in session.AllObjects<Person>())
p.Unpersist(session);
// delete (unpersist) all VelocityDbList<Person> objects created in prior run
foreach (VelocityDbList<Person> l in session.AllObjects<VelocityDbList<Person>>())
l.Unpersist(session);
Person robinHood = new Person("Robin", "Hood", 30);
Person billGates = new Person("Bill", "Gates", 56, robinHood);
Person steveJobs = new Person("Steve", "Jobs", 56, billGates);
robinHood.BestFriend = billGates;
session.Persist(steveJobs);
steveJobs.Friends.Add(billGates);
steveJobs.Friends.Add(robinHood);
billGates.Friends.Add(billGates);
robinHood.Friends.Add(steveJobs);
session.Commit();
}
using (SessionNoServer session = new SessionNoServer(s_systemDir))
{
List<FuzzyStringComparisonOptions> options = new List<FuzzyStringComparisonOptions>();
// Choose which algorithms should weigh in for the comparison
options.Add(FuzzyStringComparisonOptions.UseOverlapCoefficient);
options.Add(FuzzyStringComparisonOptions.UseLongestCommonSubsequence);
options.Add(FuzzyStringComparisonOptions.UseLongestCommonSubstring);
options.Add(FuzzyStringComparisonOptions.UseHammingDistance);
options.Add(FuzzyStringComparisonOptions.UseJaccardDistance);
options.Add(FuzzyStringComparisonOptions.UseJaroDistance);
options.Add(FuzzyStringComparisonOptions.UseJaroWinklerDistance);
options.Add(FuzzyStringComparisonOptions.UseLevenshteinDistance);
options.Add(FuzzyStringComparisonOptions.UseRatcliffObershelpSimilarity);
options.Add(FuzzyStringComparisonOptions.UseSorensenDiceDistance);
options.Add(FuzzyStringComparisonOptions.UseTanimotoCoefficient);
// Choose the relative strength of the comparison - is it almost exactly equal? or is it just close?
FuzzyStringComparisonTolerance tolerance = FuzzyStringComparisonTolerance.Normal;
session.BeginRead();
foreach (Person p in session.AllObjects<Person>())
{
// Get a boolean determination of approximate equality
foreach (string firstNameFuzzy in new string[] { "Rob", "Billy", "Mats", "Stevo", "stevo" })
{
bool result = firstNameFuzzy.ApproximatelyEquals(p.FirstName, options, tolerance);
if (result)
Console.WriteLine(firstNameFuzzy + " approximatly equals " + p.FirstName);
}
}
session.Commit();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
}
}
Database Locking
JsonExportImport - shows how to export and import VelocityDB objects to/from JSON.
using System;
using System.Collections.Generic;
using System.Linq;
using VelocityDb.Session;
using VelocityDBExtensions;
using VelocityDbSchema.Samples.Sample4;
namespace JsonExportImport
{
class JsonExportImport
{
static readonly string s_systemDirToImport = "Sample4"; // appended to SessionBase.BaseDatabasePath
static readonly string s_systemDir = "JsonExportImport"; // appended to SessionBase.BaseDatabasePath
static void Main(string[] args)
{
try
{
int personCt = 0;
using (SessionBase session = new SessionNoServer(s_systemDirToImport))
{
session.BeginRead();
IEnumerable<string> personStringEnum = session.ExportToJson<Person>();
using (SessionBase sessionImport = new SessionNoServer(s_systemDir))
{
sessionImport.BeginUpdate();
foreach (string json in personStringEnum)
{
Person person = sessionImport.ImportJson<Person>(json);
sessionImport.Persist(person);
personCt++;
}
session.Commit();
sessionImport.Commit();
Console.WriteLine("Imported " + personCt + " from Json strings");
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
}
}
High Availability
The following code shows how high availabilty is achieved using VelocityDB. Test first connects to one server with a requested backup (like replica) to another server. Then we delete all the database files from the original server and quickly make a restore to another server and continue operating with no data loss.
1: // This application shows how to accomplish High Availability with VelocityDB.
2: // It can be done with in memory data or persisted data replicated to a backup server that can take over as a master server on demand.
3:
4: using System;
5: using System.Collections.Generic;
6: using System.IO;
7: using System.Linq;
8: using System.Net;
9: using System.Text;
10: using System.Threading.Tasks;
11: using VelocityDb;
12: using VelocityDb.Session;
13: using VelocityDbSchema;
14:
15: namespace BackupRestore
16: {
17: class HighAvailability
18: {
19: static readonly string systemDir = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
20: "VelocityDB" + Path.DirectorySeparatorChar + "Databases" + Path.DirectorySeparatorChar + "HighAvailability");
21: static string systemHost = Dns.GetHostName();
22: static string backupHost = "FindPriceBuy"; // modify to second server name that you are using (make sure VelocityDB is installed on that server first)
23: static readonly string backupDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "VelocityDB", "Databases" + Path.DirectorySeparatorChar + "HighAvailabilityBackup");
24: static bool inMemoryOnly = false;
25: public static readonly uint backupLocationStartDbNum = (uint)Math.Pow(2, 26);
26: public void CreateDataWithBackupServer()
27: {
28: int loops = 30000;
29: int j;
30: using (ServerClientSession session = new ServerClientSession(systemDir, systemHost, 1000, true, inMemoryOnly))
31: {
32: Man aMan = null;
33: Woman aWoman = null;
34: const bool isBackupLocation = true;
35: session.BeginUpdate();
36: // we need to have backup locations special since server is not supposed to do encryption or compression
37: DatabaseLocation backupLocation = new DatabaseLocation(backupHost, backupDir, backupLocationStartDbNum, UInt32.MaxValue, session,
38: false, PageInfo.encryptionKind.noEncryption, isBackupLocation, session.DatabaseLocations.Default());
39: session.NewLocation(backupLocation);
40: session.Commit();
41: session.BeginUpdate();
42: for (j = 1; j <= loops; j++)
43: {
44: aMan = new Man(null, aMan, j, DateTime.Now);
45: session.Persist(aMan);
46: aWoman = new Woman(aMan, aWoman, j);
47: session.Persist(aWoman);
48: aMan.spouse = new VelocityDb.WeakIOptimizedPersistableReference<VelocityDbSchema.Person>(aWoman);
49: if (j % 1000000 == 0)
50: Console.WriteLine("Loop # " + j);
51: }
52: UInt64 id = aWoman.Id;
53: Console.WriteLine("Commit, done Loop # " + j);
54: session.Commit();
55: }
56: }
57:
58: public void CreateMoreDataWithBackupServer()
59: {
60: int loops = 1000;
61: int j;
62: using (ServerClientSession session = new ServerClientSession(systemDir, systemHost, 1000, true, inMemoryOnly))
63: {
64: Man aMan = null;
65: Woman aWoman = null;
66: session.BeginUpdate();
67: for (j = 1; j <= loops; j++)
68: {
69: aMan = new Man(null, aMan, j, DateTime.Now);
70: session.Persist(aMan);
71: aWoman = new Woman(aMan, aWoman, j);
72: session.Persist(aWoman);
73: aMan.spouse = new VelocityDb.WeakIOptimizedPersistableReference<VelocityDbSchema.Person>(aWoman);
74: if (j % 1000000 == 0)
75: Console.WriteLine("Loop # " + j);
76: }
77: UInt64 id = aWoman.Id;
78: Console.WriteLine("Commit, done Loop # " + j);
79: session.FlushUpdates();
80: ReadSomeData(); // read some with uncommited cached server data
81: session.Commit();
82: }
83: }
84:
85: public void ReadSomeData()
86: {
87: int ct = 0;
88: using (ServerClientSession session = new ServerClientSession(systemDir, systemHost, 1000, true, inMemoryOnly))
89: {
90: session.BeginRead();
91: foreach (Man man in session.AllObjects<Man>())
92: {
93: ct++;
94: }
95: Console.WriteLine("Commit, number of Men found: " + ct);
96: session.Commit();
97: }
98: }
99:
100: public void RestoreToBackupServer()
101: {
102: using (ServerClientSession session = new ServerClientSession(systemDir, systemHost))
103: {
104: session.ClearServerCache(); // normally don't use this function but use it here to simulate a server going down and restarting
105: }
106:
107: using (ServerClientSession session = new ServerClientSession(systemDir, backupHost, 1000, true, inMemoryOnly))
108: {
109: session.BeginUpdate();
110: DatabaseLocation backupLocation = new DatabaseLocation(backupHost, backupDir, backupLocationStartDbNum, UInt32.MaxValue, session,
111: false, PageInfo.encryptionKind.noEncryption, true, session.DatabaseLocations.Default());
112: session.RestoreFrom(backupLocation, DateTime.MaxValue);
113: session.Commit(false, true);
114: }
115: }
116:
117: public void DeleteBackupLocation()
118: {
119: using (ServerClientSession session = new ServerClientSession(systemDir, systemHost, 1000, true, inMemoryOnly))
120: {
121: session.BeginUpdate();
122: DatabaseLocation backupLocation = session.DatabaseLocations.LocationForDb(backupLocationStartDbNum);
123: List<Database> dbList = session.OpenLocationDatabases(backupLocation, true);
124: foreach (Database db in dbList)
125: session.DeleteDatabase(db);
126: session.DeleteLocation(backupLocation);
127: session.Commit();
128: }
129: }
130: public void DeleteDefaultLocation()
131: {
132: using (ServerClientSession session = new ServerClientSession(systemDir, systemHost, 1000, true, inMemoryOnly))
133: {
134: session.BeginUpdate();
135: DatabaseLocation defaultLocation = session.DatabaseLocations.Default();
136: List<Database> dbList = session.OpenLocationDatabases(defaultLocation, true);
137: foreach (Database db in dbList)
138: if (db.DatabaseNumber > Database.InitialReservedDatabaseNumbers)
139: session.DeleteDatabase(db);
140: session.DeleteLocation(defaultLocation);
141: session.Commit();
142: }
143: }
144:
145: static void Main(string[] args)
146: {
147: if (args.Length > 0) // pass any argument to to command line to force use of persisted data.
148: inMemoryOnly = false;
149: HighAvailability ha = new HighAvailability();
150: try
151: {
152: ha.CreateDataWithBackupServer();
153: ha.ReadSomeData();
154: ha.CreateMoreDataWithBackupServer();
155: ha.ReadSomeData();
156: if (Directory.Exists(systemDir))
157: Directory.Delete(systemDir, true); // remove our current systemDir and all its databases.
158: ha.RestoreToBackupServer();
159: string t = systemHost; // swap backupHost and systemHost
160: systemHost = backupHost;
161: backupHost = t;
162: ha.ReadSomeData();
163: ha.CreateMoreDataWithBackupServer();
164: ha.ReadSomeData();
165: ha.DeleteBackupLocation();
166: ha.DeleteDefaultLocation(); // so that we can rerun this sample
167: }
168: catch (Exception ex)
169: {
170: Console.WriteLine("Exception: {0}", ex);
171:
172: }
173: }
174: }
175: }
Indexes
Here are some classes with defined indexes
1: [UniqueConstraint]
2: [Index("registrationState,registrationPlate")]
3: public class Car : Vehicle
4: {
5: string registrationState;
6: string registrationPlate;
7: [Index]
8: InsuranceCompany insuranceCompany;
9: string insurancePolicy;
10:
11: public Car(string color, int maxPassengers, int fuelCapacity, double litresPer100Kilometers, DateTime modelYear,
12: string brandName, string modelName, int maxSpeed, int odometer, string registrationState, string registrationPlate,
13: InsuranceCompany insuranceCompany, string insurancePolicy)
14: : base(color, maxPassengers, fuelCapacity, litresPer100Kilometers, modelYear, brandName, modelName, maxSpeed, odometer)
15: {
16: this.registrationState = registrationState;
17: this.registrationPlate = registrationPlate;
18: this.insuranceCompany = insuranceCompany;
19: this.insurancePolicy = insurancePolicy;
20: }
21: }
22:
23: [Index("stateOrCountry,licenseNumber")]
24: public class DriversLicense : OptimizedPersistable
25: {
26: string stateOrCountry;
27: string licenseNumber;
28: DateTime dateIssued;
29:
30: [Index]
31: DateTime validUntil;
32:
33: public DriversLicense(string stateOrCountry, string licenseNumber, DateTime validUntil)
34: {
35: this.stateOrCountry = stateOrCountry;
36: this.licenseNumber = licenseNumber;
37: this.dateIssued = DateTime.Now;
38: this.validUntil = validUntil;
39: }
40:
41: [FieldAccessor("validUntil")]
42: public DateTime ValidUntil
43: {
44: get
45: {
46: return validUntil;
47: }
48: }
49: }
50:
51: public class InsuranceCompany : OptimizedPersistable
52: {
53: [Index]
54: [UniqueConstraint]
55: [OnePerDatabase]
56: string name;
57: string phoneNumber;
58:
59: public InsuranceCompany(string name, string phoneNumber)
60: {
61: this.name = name;
62: this.phoneNumber = phoneNumber;
63: }
64:
65: [FieldAccessor("name")]
66: public string Name
67: {
68: get
69: {
70: return name;
71: }
72: }
73: }
74:
75: [Index]
76: public class Person : OptimizedPersistable
77: {
78: string name;
79: DriversLicense license;
80:
81: public Person(string name, DriversLicense license)
82: {
83: this.name = name;
84: this.license = license;
85: }
86: }
87:
88: public class Truck : Vehicle
89: {
90: string registrationState;
91: string registrationPlate;
92: InsuranceCompany insuranceCompany;
93: string insurancePolicy;
94: int cargoCapacity; // in Kg
95:
96: public Truck(string color, int maxPassengers, int fuelCapacity, double litresPer100Kilometers, DateTime modelYear,
97: string brandName, string modelName, int maxSpeed, int odometer, string registrationState, string registrationPlate,
98: InsuranceCompany insuranceCompany, string insurancePolicy, int cargoCapacity)
99: : base(color, maxPassengers, fuelCapacity, litresPer100Kilometers, modelYear, brandName, modelName, maxSpeed, odometer)
100: {
101: this.registrationState = registrationState;
102: this.registrationPlate = registrationPlate;
103: this.insuranceCompany = insuranceCompany;
104: this.insurancePolicy = insurancePolicy;
105: this.cargoCapacity = cargoCapacity;
106: }
107: }
108: [Index("modelYear,brandName,modelName,color")]
109: public abstract class Vehicle : OptimizedPersistable
110: {
111: [Index]
112: string color;
113: int maxPassengers;
114: int fuelCapacity; // fuel capacity in liters
115: [Index]
116: double litresPer100Kilometers; // fuel cunsumption
117: DateTime modelYear;
118: [Index]
119: [IndexStringByHashCode]
120: string brandName;
121: string modelName;
122: int maxSpeed; // km/h
123: int odometer; // km
124:
125: protected Vehicle(string color, int maxPassengers, int fuelCapacity, double litresPer100Kilometers, DateTime modelYear, string brandName, string modelName, int maxSpeed, int odometer)
126: {
127: this.color = color;
128: this.maxPassengers = maxPassengers;
129: this.fuelCapacity = fuelCapacity;
130: this.litresPer100Kilometers = litresPer100Kilometers;
131: this.modelYear = modelYear;
132: this.brandName = brandName;
133: this.modelName = modelName;
134: this.maxSpeed = maxSpeed;
135: this.odometer = odometer;
136: }
137:
138: [FieldAccessor("color")]
139: public string Color
140: {
141: get
142: {
143: return color;
144: }
145: set
146: {
147: Update();
148: color = value;
149: }
150: }
151:
152: [FieldAccessor("litresPer100Kilometers")]
153: public double LitresPer100Kilometers
154: {
155: get
156: {
157: return litresPer100Kilometers;
158: }
159: }
160: }
Using these indexes
1: class Indexes
2: {
3: static readonly string systemDir = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
4: "VelocityDB" + Path.DirectorySeparatorChar + "Databases" + Path.DirectorySeparatorChar + "Indexes");
5:
6: static void Main(string[] args)
7: {
8: try
9: {
10: string brandName = "Toyota";
11: string color = "Blue";
12: int maxPassengers = 5;
13: int fuelCapacity = 40;
14: double litresPer100Kilometers = 5;
15: DateTime modelYear = new DateTime(2003, 1, 1);
16: string modelName = "Highlander";
17: int maxSpeed = 200;
18: int odometer = 100000;
19: string registrationState = "Texas";
20: string registrationPlate = "TX343434";
21: string insurancePolicy = "CAA7878787";
22: DriversLicense license = new DriversLicense("California", "B7788888", DateTime.Now + new TimeSpan(1825, 0, 0, 0));
23: Person person = new Person("Mats Persson", license);
24: InsuranceCompany insuranceCompany = new InsuranceCompany("Allstate", "858727878");
25: Car car = new Car(color, maxPassengers, fuelCapacity, litresPer100Kilometers, modelYear, brandName, modelName, maxSpeed,
26: odometer, registrationState, registrationPlate, insuranceCompany, insurancePolicy);
27: using (SessionNoServer session = new SessionNoServer(systemDir))
28: { // cleanup data from a possible prior run
29: session.BeginUpdate();
30: foreach (Database db in session.OpenAllDatabases(true))
31: if (db.DatabaseNumber >= 10 || db.DatabaseNumber == SessionBase.IndexDescriptorDatabaseNumber)
32: session.DeleteDatabase(db);
33: session.Commit();
34: }
35: using (SessionNoServer session = new SessionNoServer(systemDir))
36: {
37: session.BeginUpdate();
38: session.Persist(car);
39: registrationState = "Maine";
40: car = new Car(color, maxPassengers, fuelCapacity, litresPer100Kilometers, modelYear, brandName, modelName, maxSpeed,
41: odometer, registrationState, registrationPlate, insuranceCompany, insurancePolicy);
42: session.Persist(car);
43: color = "Red";
44: maxPassengers = 5;
45: fuelCapacity = 50;
46: litresPer100Kilometers = 8;
47: modelYear = new DateTime(2006, 1, 1);
48: brandName = "Toyota";
49: modelName = "Tacoma";
50: maxSpeed = 210;
51: odometer = 50000;
52: registrationState = "Texas";
53: registrationPlate = "TX343433";
54: insurancePolicy = "CAA7878777";
55: car = new Car(color, maxPassengers, fuelCapacity, litresPer100Kilometers, modelYear, brandName, modelName, maxSpeed,
56: odometer, registrationState, registrationPlate, insuranceCompany, insurancePolicy);
57: session.Persist(car);
58: color = "Black";
59: maxPassengers = 5;
60: fuelCapacity = 60;
61: litresPer100Kilometers = 3;
62: modelYear = new DateTime(2001, 1, 1);
63: brandName = "Lincoln";
64: modelName = "Town Car";
65: maxSpeed = 220;
66: odometer = 250000;
67: registrationState = "Texas";
68: registrationPlate = "TX543433";
69: insurancePolicy = "CAA7878775";
70: car = new Car(color, maxPassengers, fuelCapacity, litresPer100Kilometers, modelYear, brandName, modelName, maxSpeed,
71: odometer, registrationState, registrationPlate, insuranceCompany, insurancePolicy);
72: session.Persist(car);
73: session.Commit();
74: }
75: using (SessionNoServer session = new SessionNoServer(systemDir))
76: {
77: session.BeginRead();
78: Console.WriteLine("Blue Cars");
79: BTreeSet<Car> bTree = session.Index<Car>("color");
80: foreach (Car c in (from aCar in bTree where aCar.Color == "Blue" select aCar))
81: Console.WriteLine(c.ToStringDetails(session));
82: Console.WriteLine("Cars in fuel efficierncy order");
83: foreach (Car c in session.Index<Car>("litresPer100Kilometers"))
84: Console.WriteLine(c.ToStringDetails(session));
85: Console.WriteLine("Vehicles ordered modelYear, brandName, modelName, color");
86: foreach (Vehicle v in session.Index<Vehicle>())
87: Console.WriteLine(v.ToStringDetails(session));
88: session.Commit();
89: }
90: using (SessionNoServer session = new SessionNoServer(systemDir))
91: {
92: session.BeginUpdate();
93: // these LINQ statements will trigger a binary search lookup (not a linear serach) of the matching Car objects in the BTreeSet
94: Car c = (from aCar in session.Index<Car>("color") where aCar.Color == "Blue" select aCar).First();
95: c.Color = "Green";
96: session.Commit();
97: }
98: using (SessionNoServer session = new SessionNoServer(systemDir))
99: {
100: session.BeginUpdate();
101: // these LINQ statements will trigger a binary search lookup (not a linear serach) of the matching Car objects in the BTreeSet
102: Car c = (from aCar in session.Index<Car>("color") where aCar.Color == "Green" select aCar).First();
103: UInt64 id = c.Id;
104: session.DeleteObject(id);
105: session.Abort();
106: session.BeginUpdate();
107: session.DeleteObject(id);
108: session.Commit();
109: }
110: using (SessionNoServer session = new SessionNoServer(systemDir))
111: {
112: Stopwatch sw = new Stopwatch();
113: sw.Start();
114: session.BeginRead();
115: // these LINQ statements will trigger a binary search lookup (not a linear serach) of the matching Car objects in the BTreeSet
116: Console.WriteLine("Blue Cars");
117: foreach (Car c in (from aCar in session.Index<Car>("color") where aCar.Color == "Blue" select aCar))
118: Console.WriteLine(c.ToStringDetails(session));
119: session.Commit();
120: sw.Stop();
121: Console.WriteLine(sw.Elapsed);
122: }
123: using (SessionNoServer session = new SessionNoServer(systemDir))
124: {
125: Stopwatch sw = new Stopwatch();
126: sw.Start();
127: session.BeginUpdate();
128: for (int i = 0; i < 10000; i++)
129: { // add some junk to make search harder
130: car = new Car(color, maxPassengers, fuelCapacity, litresPer100Kilometers, modelYear, brandName, modelName, i,
131: odometer, registrationState, registrationPlate + i, insuranceCompany, insurancePolicy);
132: session.Persist(car);
133: }
134: session.Commit();
135: sw.Stop();
136: Console.WriteLine(sw.Elapsed);
137: }
138: using (SessionNoServer session = new SessionNoServer(systemDir))
139: {
140: Stopwatch sw = new Stopwatch();
141: sw.Start();
142: session.BeginRead();
143: // these LINQ statements will trigger a binary search lookup (not a linear serach) of the matching Car objects in the BTreeSet
144: Console.WriteLine("Blue Cars");
145: foreach (Car c in (from aCar in session.Index<Car>("color") where aCar.Color == "Blue" select aCar))
146: Console.WriteLine(c.ToStringDetails(session));
147: session.Commit();
148: sw.Stop();
149: Console.WriteLine(sw.Elapsed);
150: }
151: using (SessionNoServer session = new SessionNoServer(systemDir))
152: {
153: Stopwatch sw = new Stopwatch();
154: sw.Start();
155: session.BeginUpdate();
156: Car c = (from aCar in session.Index<Car>("color") where aCar.Color == "Blue" select aCar).First();
157: c.Unpersist(session);
158: session.Commit();
159: sw.Stop();
160: Console.WriteLine(sw.Elapsed);
161: }
162: using (SessionNoServer session = new SessionNoServer(systemDir))
163: {
164: Stopwatch sw = new Stopwatch();
165: sw.Start();
166: session.BeginRead();
167: foreach (Car c in session.Index<Car>())
168: Console.WriteLine(c.ToStringDetails(session));
169: Console.WriteLine("Blue Cars");
170: foreach (Car c in (from aCar in session.Index<Car>() where aCar.Color == "Blue" select aCar))
171: Console.WriteLine(c.ToStringDetails(session));
172: session.Commit();
173: sw.Stop();
174: Console.WriteLine(sw.Elapsed);
175: }
176: using (SessionNoServer session = new SessionNoServer(systemDir))
177: {
178: Stopwatch sw = new Stopwatch();
179: sw.Start();
180: session.BeginUpdate();
181: InsuranceCompany prior = insuranceCompany;
182: try
183: {
184: for (int i = 0; i < 100000; i++)
185: {
186: insuranceCompany = new InsuranceCompany("AAA", "858787878");
187: session.Persist(insuranceCompany);
188: }
189: Debug.Assert(false); // should not get here
190: }
191: catch (UniqueConstraintException)
192: {
193: }
194: session.Commit();
195: sw.Stop();
196: Console.WriteLine(sw.Elapsed);
197: }
198: using (SessionNoServer session = new SessionNoServer(systemDir))
199: {
200: Stopwatch sw = new Stopwatch();
201: sw.Start();
202: session.BeginRead();
203: Database db = session.OpenDatabase(session.DatabaseNumberOf(typeof(InsuranceCompany)));
204: var q = from company in session.Index<InsuranceCompany>("name", db) where company.Name == "AAA" select company;
205: foreach (InsuranceCompany company in q)
206: Console.WriteLine(company.ToStringDetails(session)); // only one will match
207: session.Commit();
208: sw.Stop();
209: Console.WriteLine(sw.Elapsed);
210: }
211: }
212: catch (Exception ex)
213: {
214: Console.WriteLine(ex.ToString());
215: }
216: }
217: }
Change Event Subscription and Notification
1: // This sample console application demonstrates the usage of the event subscription ServerClientSession api. Get notified when other sessions changes objects your session is intrested in.
2: using System;
3: using System.Collections.Generic;
4: using System.IO;
5: using System.Linq;
6: using System.Text;
7: using System.Threading;
8: using System.Threading.Tasks;
9: using VelocityDb;
10: using VelocityDb.Session;
11: using VelocityDbSchema;
12:
13: namespace EventSubscriber
14: {
15: class EventSubscriber
16: {
17: static readonly string systemDir = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
18: "VelocityDB" + Path.DirectorySeparatorChar + "Databases" + Path.DirectorySeparatorChar + "EventSubscriber");
19:
20: static void Main(string[] args)
21: {
22: using (ServerClientSession session = new ServerClientSession(systemDir))
23: {
24: session.BeginUpdate();
25: session.SubscribeToChanges(typeof(Person));
26: session.SubscribeToChanges(typeof(Woman), "OlderThan50");
27: Person robinHood = new Person("Robin", "Hood", 30, 1234, null, null);
28: session.Persist(robinHood);
29: Person billGates = new Person("Bill", "Gates", 56, 234, robinHood, null);
30: session.Persist(billGates);
31: Person steveJobs = new Person("Steve", "Jobs", 56, 456, billGates, null);
32: session.Persist(steveJobs);
33: session.Commit();
34: Thread t = new Thread(UpdaterThread);
35: t.Start();
36: Thread.Sleep(600);
37:
38: for (int i = 0; i < 50; i++)
39: {
40: List<Oid> changes = session.BeginReadWithEvents();
41: if (changes.Count == 0)
42: {
43: Console.WriteLine("No changes events at: " + DateTime.Now.ToString("HH:mm:ss:ms"));
44: Thread.Sleep(250);
45: }
46: foreach (Oid id in changes)
47: {
48: object obj = session.Open(id);
49: Console.WriteLine("Received change event for: " + obj + " at: " + DateTime.Now.ToString("HH:mm:ss:ms"));;
50: //session.UnsubscribeToChanges(typeof(Person));
51: }
52: Console.WriteLine();
53: session.Commit();
54: }
55: t.Join();
56: }
57: }
58:
59: static void UpdaterThread()
60: {
61: using (ServerClientSession session = new ServerClientSession(systemDir))
62: {
63: session.BeginUpdate();
64: Person Mats = new Person("Mats", "Persson", 22, 1234, null, null);
65: session.Persist(Mats);
66: Woman Kinga = new Woman("Kinga", "Persson", 56, 234, null, Mats);
67: foreach (Person p in session.AllObjects<Person>())
68: {
69: p.Age = (ushort) (p.Age + 1);
70: }
71: session.Persist(Kinga);
72: session.Commit();
73: // 5 events
74: Thread.Sleep(5000);
75:
76: session.BeginUpdate();
77: Woman Lidia = new Woman("Lidia", "Persson", 22, 1234, null, null);
78: session.Persist(Lidia);
79: session.Commit();
80: // 0 events
81: Thread.Sleep(500);
82:
83: session.BeginUpdate();
84: Woman Margareta = new Woman("Margareta", "Persson", 98, 1234, null, null);
85: session.Persist(Margareta);
86: session.Commit();
87: // 1 event
88: Thread.Sleep(500);
89:
90: session.BeginUpdate();
91: Woman Oliwia = new Woman("Oliwia", "Persson", 50, 1234, null, null);
92: session.Persist(Oliwia);
93: session.Commit();
94: // 0 events
95: Thread.Sleep(500);
96:
97: session.BeginUpdate();
98: foreach (Woman p in session.AllObjects<Woman>())
99: {
100: p.Age = (ushort) (p.Age + 1);
101: }
102: session.Commit();
103: // 3 events
104: session.BeginUpdate();
105: foreach (Woman p in session.AllObjects<Woman>())
106: {
107: p.Age = (ushort)(p.Age + 1);
108: }
109: session.Commit();
110: // 3 events
111: }
112: }
113: }
114: }
Using weak references as a way to limit graph pinned into memory
public class Person : OptimizedPersistable
{
static Random randGen = new Random(5);
string firstName;
string lastName;
WeakReference<VelocityDbList<Person>> friendsRef;
public Person(Person person = null) // creates a random Person object
{
int r = randGen.Next(99999);
firstName = r.ToString();
r = randGen.Next(99999999);
lastName = r.ToString();
VelocityDbList<Person> personList = new VelocityDbList<Person>();
if (person != null && person.IsPersistent)
{
personList.Persist(person.Session, person);
personList.Add(person);
friendsRef = new WeakReference<VelocityDbList<Person>>(personList);
}
}
public string FirstName
{
get
{
return firstName;
}
set
{
Update();
firstName = value;
}
}
public VelocityDbList<Person> Friends
{
get
{
return friendsRef.GetTarget(false, null);
}
}
}
Usage
class Program
{
static readonly string systemDir = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "VelocityDB", "Databases", "WeakReferences");
const long numberOfPersons = 10000000000; // a billion Person objects - let's say it is more than we can fit in memory
static void Main(string[] args)
{
try
{
using (SessionNoServer session = new SessionNoServer(systemDir))
{
session.BeginUpdate();
Person person = new Person();
for (long i = 0; i < numberOfPersons; i++)
{
// Each WeakReference require a persisted object (non null Oid) so that object reference can be substituted with an Oid.
session.Persist(person);
// create new Person and make prior Person his/her friend (see constructor of Person)
person = new Person(person);
}
session.Commit();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
Storing AllSupported instance
The class AllSupported contains sample data fields of all (or most) kinds of
types that have beed tested with VelocityDb. Let us know if we missed any kind of field type.
AllSupported.cs
public class AllSupported : OptimizedPersistable
{
enum byteEnum : byte { a, b, c };
enum int16Enum : short { a, b, c, d, e, f };
enum int32Enum : int { a, b, c, d, e, f, g, h };
enum int64Enum : long { a, b, c, dd, ee, ff };
int[][] jaggedArray = new int[3][];
Person person;
Pet aPet; // just a sample using a class that is not a subclass of OptimizedPersistable
byteEnum enumByte;
int16Enum enumInt16;
int32Enum enumInt32;
int64Enum enumInt64;
PersistenceByInterfaceSnake aSnake;
byte aByte;
SByte sByte;
string aString;
char aChar;
public float single;
public double aDouble;
public UInt16 uint16;
public UInt32 uint32;
public UInt64 uint64;
public Int16 int16;
public Int32 int32;
public Int64 int64;
public DateTime dateTime;
public TimeSpan timeSpan;
public Decimal aDecimal;
byte? nullableByte;
SByte? nullablesByte;
char? nullableChar;
public float? nullablesingle;
public double? nullableaDouble;
public UInt16? nullableuint16;
public UInt32? nullableuint32;
public UInt64? nullableuint64;
public Int16? nullableint16;
public Int32? nullableint32;
public Int64? nullableint64;
public DateTime? nullabledateTime;
public TimeSpan? nullabletimeSpan;
public Decimal? nullableDecimal;
WeakReference<OptimizedPersistable> weakReference;
byte?[] nullablebyteArray;
char?[] nullablecharArray;
UInt16?[] nullableuint16Array;
UInt32?[] nullableuint32Array;
UInt64?[] nullableuint64Array;
Int16?[] nullableint16Array;
Int32?[] nullableint32Array;
Int64?[] nullableint64Array;
float?[] nullablefloatArray;
double?[] nullabledoubleArray;
DateTime?[] nullableDateTimeArray;
Decimal?[] nullableDecimalArray;
Oid?[] nullableOidArray;
byte[] byteArray;
char[] charArray;
UInt16[] uint16Array;
UInt32[] uint32Array;
UInt64[] uint64Array;
Int16[] int16Array;
Int32[] int32Array;
Int64[] int64Array;
float[] floatArray;
double[] doubleArray;
DateTime[] dateTimeArray;
Oid[] oidArray;
List<byte> listByte; // all List<> use wrapper OptimizedPersistable looked up from a parent collection
List<Person> personList;
List<WeakReference<OptimizedPersistable>> weakReferenceList;
List<Int16> int16List;
List<UInt16> uint16List;
List<Int32> int32List;
List<UInt32> uint32List;
List<Int64> int64List;
List<UInt64> uint64List;
List<String> stringList;
List<Oid> oidList;
List<Oid?> nullableoidList;
[UseOidShort]
List<Pet> petListOidShort;
List<Pet> petListLongOid;
VelocityDbList<byte> odblistByte; // VelocityDbList is like List but is a subclass of OptimizedPersistable which makes it perform better by avoiding collection lookup
VelocityDbList<Person> personOdbList;
VelocityDbList<WeakReference<OptimizedPersistable>> weakReferenceOdbList;
VelocityDbList<Int16> int16OdbList;
VelocityDbList<UInt16> uint16OdbList;
VelocityDbList<Int32> int32OdbList;
VelocityDbList<UInt32> uint32OdbList;
VelocityDbList<Int64> int64OdbList;
VelocityDbList<UInt64> uint64OdbList;
VelocityDbList<String> stringOdbList;
VelocityDbList<Pet> petOdbList;
ArrayList petList2;
public Slot aSlot;
public Slot[] m_slots;
BTreeSet<Person> bTreePerson;
SortedSetAny<Person> sortedSetPerson;
SortedMap<byte, Person> sortedMapByteToPerson;
VelocityDbHashSet<Person> personHashSet;
public struct Slot
{
public int hashCode;
public Person value;
public int next;
}
public AllSupported(Int32 arraySize)
{
aSnake = new PersistenceByInterfaceSnake("Curly", 1, true, 58);
jaggedArray[0] = new int[] { 1, 3, 5, 7, 9 };
jaggedArray[1] = new int[] { 0, 2, 4, 6 };
jaggedArray[2] = new int[] { 11, 22 };
nullabledateTime = null;
nullableByte = null;
enumByte = byteEnum.b;
enumInt16 = int16Enum.c;
enumInt32 = int32Enum.f;
enumInt64 = int64Enum.ff;
byteArray = new byte[arraySize];
charArray = new char[arraySize];
uint16Array = new UInt16[arraySize];
uint32Array = new UInt32[arraySize];
uint64Array = new UInt64[arraySize];
int16Array = new Int16[arraySize];
int32Array = new Int32[arraySize];
int64Array = new Int64[arraySize];
floatArray = new float[arraySize];
doubleArray = new double[arraySize];
dateTimeArray = new DateTime[arraySize];
oidArray = new Oid[arraySize];
nullablebyteArray = new byte?[arraySize];
nullablecharArray = new char?[arraySize];
nullableuint16Array = new UInt16?[arraySize];
nullableuint32Array = new UInt32?[arraySize];
nullableuint64Array = new UInt64?[arraySize];
nullableint16Array = new Int16?[arraySize];
nullableint32Array = new Int32?[arraySize];
nullableint64Array = new Int64?[arraySize];
nullablefloatArray = new float?[arraySize];
nullabledoubleArray = new double?[arraySize];
nullableDateTimeArray = new DateTime?[arraySize];
nullableDecimalArray = new Decimal?[arraySize];
nullableOidArray = new Oid?[arraySize];
listByte = new List<byte>(arraySize); // just samples of what Key can be
personList = new List<Person>(arraySize);
petListOidShort = new List<Pet>(arraySize);
petListLongOid = new List<Pet>(arraySize);
petList2 = new ArrayList(arraySize);
int32List = new List<Int32>(arraySize);
uint32List = new List<UInt32>(arraySize);
uint64List = new List<ulong>(arraySize);
oidList = new List<Oid>(arraySize);
nullableoidList = new List<Oid?>(arraySize);
personHashSet = new VelocityDbHashSet<Person>();
person = new Person();
timeSpan = new TimeSpan(1, 0, 0);
aPet = new Cat("Boze", 5);
petListOidShort.Add(aPet);
petListLongOid.Add(aPet);
petList2.Add(aPet);
uint32List.Add(5555);
int32List.Add(-66666);
uint64List.Add(8989898988989);
doubleArray[0] = 0.2323232323232;
aSlot = new Slot();
aSlot.value = new Person();
m_slots = new Slot[5];
nullableoidList.Add(new Oid((ulong)4444));
nullableoidList.Add(null);
nullableoidList.Add(new Oid((ulong)8888));
if (arraySize > 0)
{
oidArray[0] = new Oid((ulong)99999);
nullableOidArray[0] = new Oid((ulong)99999);
nullableint32Array[0] = 5;
}
if (arraySize > 2)
{
oidArray[2] = new Oid((ulong)66666);
nullableOidArray[2] = new Oid((ulong)66666);
nullableint32Array[2] = 6;
}
for (int i = 0; i < 5; i++)
{
m_slots[i].hashCode = i;
m_slots[i].value = new Person();
m_slots[i].next = i + 1;
}
}
}
Pet.cs
[Serializable]
public class Pet
{
string name;
short age;
public List<Pet> friends;
public Pet() { }
public Pet(string aName, short anAge)
{
name = aName;
age = anAge;
friends = new List<Pet>(2);
}
public string Name
{
get
{
return name;
}
set
{
name = value;
}
}
}
Cat.cs
[Serializable]
public class Cat : Pet
{
public string color;
public Cat() { } // used by Activator.CreateInstance for non OptimizedPersistable subclasses and value types
public Cat(string aName, short anAge, string color = "black") : base(aName, anAge)
{
this.color = color;
}
}
Main Program of AllSupported sample
class Program
{
static readonly string systemDir = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "VelocityDB", "Databases", "AllSupportedSample");
static void Main(string[] args)
{
UInt64 id;
AllSupported allSupported, allSupported2;
try
{
using (SessionNoServer session = new SessionNoServer(systemDir))
{
session.BeginUpdate();
allSupported = new AllSupported(3);
session.Persist(allSupported);
id = allSupported.Id;
session.Commit();
}
using (SessionNoServer session = new SessionNoServer(systemDir))
{
session.BeginRead();
allSupported2 = (AllSupported)session.Open(id);
session.Commit();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
}
Looking at some of the objects created
SortedObjects
Shows how to use a BTreeSet and a LINQ query taking advantage of the efficient BTreeSet lookup
using System;
using System.Collections.Generic;
using System.Linq;
using VelocityDb;
using VelocityDb.Session;
using VelocityDb.Collection.BTree;
using VelocityDb.Collection.Comparer;
using VelocityDbSchema.Samples.AllSupportedSample;
using System.IO;
namespace SortedObjects
{
class SortedObjects
{
static readonly string systemDir = "SortedObjects"; // appended to SessionBase.BaseDatabasePath for a full path
static void Main(string[] args)
{
try
{
Oid bTreeId;
bool createOnly = args.Length > 0;
UInt64 someRandomPersonsIdNumber = 0;
using (SessionNoServer session = new SessionNoServer(systemDir))
{
const UInt32 numberOfPersons = 1000000;
const ushort nodeMaxSize = 5000;
const ushort comparisonByteArraySize = sizeof(UInt64); // enough room to hold entire idNumber of a Person
const bool comparisonArrayIsCompleteKey = true;
const bool addIdCompareIfEqual = false;
Person person;
session.BeginUpdate();
CompareByField<Person> compareByField = new CompareByField<Person>("idNumber", session, addIdCompareIfEqual);
BTreeSet<Person> bTree = new BTreeSet<Person>(compareByField, session, nodeMaxSize, comparisonByteArraySize, comparisonArrayIsCompleteKey);
session.Persist(bTree); // Persist the root of the BTree so that we have something persisted that can be flushed to disk if memory available becomes low
for (int i = 0; i < numberOfPersons; i++)
{
person = new Person();
if (i % 1000 == 0)
someRandomPersonsIdNumber = person.IdNumber;
bTree.AddFast(person);
}
bTreeId = bTree.Oid;
session.Commit();
}
if (!createOnly)
using (SessionNoServer session = new SessionNoServer(systemDir))
{
session.BeginRead();
BTreeSet<Person> bTree = (BTreeSet<Person>)session.Open(bTreeId);
foreach (Person person in (IEnumerable<Person>)bTree)
{
if (person.IdNumber > 196988888791402)
{
Console.WriteLine(person);
break;
}
}
session.Commit();
session.BeginRead();
Person lookupPerson = new Person(someRandomPersonsIdNumber);
UInt64 id = bTree.GetKeyId(lookupPerson); // lookup without opening object having the key field value of someRandomPersonsIdNumber
Person lookedUpPerson = null;
bTree.TryGetKey(lookupPerson, ref lookedUpPerson);
if (id != lookedUpPerson.Id)
throw new UnexpectedException("Should match");
// this LINQ statement will trigger a binary search lookup (not a linear serach) of the matching Person objects in the BTreeSet
Console.WriteLine((from person in bTree where person.IdNumber > 196988888791402 select person).First());
session.Commit();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
}
}
DesEncrypted
class Program
{
const UInt32 desEncryptedStartDatabaseNumber = 10;
const bool compressPages = true;
static readonly string systemDir = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "VelocityDB", "Databases", "DesEncrypted");
static readonly string desEncryptedLocation = System.IO.Path.Combine(systemDir + "desEncryptedLocation");
static void Main(string[] args)
{
try
{
using (SessionNoServer session = new SessionNoServer(systemDir))
{
DatabaseLocation localLocation = new DatabaseLocation(Dns.GetHostName(), desEncryptedLocation, desEncryptedStartDatabaseNumber, UInt32.MaxValue,
session, compressPages, PageInfo.encryptionKind.desEncrypted);
session.BeginUpdate();
session.NewLocation(localLocation);
localLocation.DesKey = Page.StringToByteArray("5d9nndwy"); // Des keys are 8 bytes long
Person robinHood = new Person("Robin", "Hood", 30);
Person billGates = new Person("Bill", "Gates", 56, robinHood);
Person steveJobs = new Person("Steve", "Jobs", 56, billGates);
robinHood.BestFriend = billGates;
session.Persist(steveJobs);
steveJobs.Friends.Add(billGates);
steveJobs.Friends.Add(robinHood);
billGates.Friends.Add(billGates);
robinHood.Friends.Add(steveJobs);
session.Commit();
}
using (SessionNoServer session = new SessionNoServer(systemDir))
{ // Des keys are not persisted in DatabaseLocation (for safety). Instead they are stored as *.des files
// in the users document directory of the user that created the DatabaseLocation. These files can be copied
// to other user's document directory when acccess is desired for other users.
// Path to user document dir is given by C#: Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
session.BeginRead();
Database db = session.OpenDatabase(session.DatabaseNumberOf(typeof(Person)));
foreach (Page page in db)
{
foreach (OptimizedPersistable obj in page)
{
Person person = obj as Person;
if (person != null)
Console.WriteLine(person.FirstName);
}
}
session.Commit();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
}
UpdateClass
This sample illustrates the support for changing class definition of persistently stored objects
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using VelocityDb;
using VelocityDb.TypeInfo;
using VelocityDb.Session;
using VelocityDbSchema.Samples.UpdateClass;
using System.IO;
using System.Diagnostics;
namespace UpdateClass
{
/// <summary>
/// Test updating a class that already exist in the Database schema, rerun multiple times. Modify class in between runs. Check objects by browsing them with VelocityDbBrowser
/// </summary>
public class UpdateClass
{
static readonly string systemDir = "UpdateClass";
static int Main(string[] args)
{
try
{
UpdatedClass updatedClassObject;
int ct1 = 0;
using (SessionNoServer session = new SessionNoServer(systemDir))
{
session.BeginUpdate();
session.UpdateClass(typeof(UpdatedClass)); // call this when you have updated the class since first storing instances of this type or since last call to UpdateClass
UInt32 dbNum = session.DatabaseNumberOf(typeof(UpdatedClass));
foreach (UpdatedClass obj in session.AllObjects<UpdatedClass>())
{
Console.Write(obj.ToString() + " has members: ");
foreach (DataMember member in obj.GetDataMembers())
{
Console.Write(member.ToString() + " ");
}
Console.WriteLine();
obj.UpdateTypeVersion(); // comment out if you DO NOT want to migrate this object to the latest version of the class
ct1++;
}
int ct2 = 0;
Database db = session.OpenDatabase(dbNum, true, false);
if (db != null)
foreach (UpdatedClass obj in db.AllObjects<UpdatedClass>())
ct2++;
Debug.Assert(ct1 == ct2);
updatedClassObject = new UpdatedClass();
session.Persist(updatedClassObject);
session.Commit();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
return 1;
}
return 0;
}
}
}
Using LINQ
Sometimes it is convenient to use LINQ to get data the way you want it. We use
it in the IssueTracker that we have online at VelocityDB.com. As you see
deploying an asp.net using VelocityDB is easy. The only issue is updating the
host and path of DatabaseLocations used.
public ICollection<ProductVersion> AllVersions(string sortExpression)
{
try
{
string dataPath = HttpContext.Current.Server.MapPath("~/tracker");
using (SessionNoServer session = new SessionNoServer(dataPath, false, 2000, true, false))
{
session.BeginRead();
IssueTracker bugTracker = (IssueTracker)session.Open(IssueTracker.PlaceInDatabase, 1, 1, false);
ICollection<ProductVersion> versionSet = bugTracker.VersionSet.Keys;
if (sortExpression.Length > 0)
{
string[] selectAndDir = sortExpression.Split(' ');
int sorting = int.Parse(selectAndDir[0]);
bool reverse = selectAndDir.Length > 1;
switch (sorting)
{
case 1: versionSet = (from version in versionSet orderby version.Name select version).ToList();
break;
case 2: versionSet = (from version in versionSet orderby version.Description select version).ToList();
break;
case 3: versionSet = (from version in versionSet orderby version.ReleaseDate select version).ToList();
break;
case 4: versionSet = (from version in versionSet orderby version.CreatedBy select version).ToList();
break;
}
if (reverse)
{
List<ProductVersion> tempList = new List<ProductVersion>(versionSet.Count);
IEnumerable<ProductVersion> temp = versionSet.Reverse<ProductVersion>();
foreach (ProductVersion issue in temp)
{
tempList.Add(issue);
}
versionSet = tempList;
}
}
session.Commit();
return versionSet;
}
}
catch (System.Exception ex)
{
this.errorLabel.Text = ex.ToString();
}
return null;
}
Wikipedia
Here we import the entire collection of Wikipedia articles/subjects. Wikipedia is available as one giant XML file, the file is 48 GB large (uncompressed). You can download the compressed file (~9 GB) from
here. Uncompress it using 7-zip.
The import to VelocityDB databases is very fast, it takes about 20 minutes to read, parse and store all 652,870,281 lines of text into 80 structured VelocityDB databases (from & to a spinning disk). The sample program then continues
by creating an inverted index of all 14,659,817 Wikipedia articles (782,745,622 lines of XML text), the index is created using parallel threads.
All the C# source code for this sample is provided in our download.
WorldCities
Loads World Cities with population from a csv file (~about 2.7 million records) provided by MaxMind.
After loading the city data, we attempt to mimic the behavior of QlikView.
A ListBoxItem that is selected has a green background, an associated value has a white background and non-associated values have a light gray background.
You can select single cells or multiple cells in each column and see how the associations (colors) change. QlikView is a very successful product with revenue around $260 million/year.
The product was invented and mostly coded by my fellow Swede,
Håkan Wolgé
KevinBaconNumbers
ImdbImport imports from two compressed text files containing actors, actresses and movie data.
The data comes from IMDB
The KeveinBaconNumers application computes the degree of seperation between Kevin Bacon and
all other actors and actresses (~ 2 million) taking part in about 350,000 movies.
0 degrees means you are Kevin Bacon
1 degree, you acted in one of Kevin Bacon's movies
2 degrees, you acted in a movie with someone who acted in the same movie as Kevin Bacon
and so on...
The output looks similar to Oracle of Bacon (which
by the way is not using an Oracle database!)
[c:\VelocityDb\Release]timer& KevinBaconNumbers.exe& timer
Timer 1 on: 22:29:01
Degree 0 has # of people: 1
Degree 1 has # of people: 3475
Degree 2 has # of people: 385345
Degree 3 has # of people: 894996
Degree 4 has # of people: 121903
Degree 5 has # of people: 7462
Degree 6 has # of people: 446
Degree 7 has # of people: 28
Degree 8 has # of people: 0
Degree 9 has # of people: 0
Timer 1 off: 22:29:28 Elapsed: 0:00:26.94
The entire C# source code for these two applications are part of the download of VelocityDB, download it
for free from here.
We ran this on a desktop PC, the same
one that was used for the triangle counter.
How would you compute this matrix using only SQL code? We bet it wouldn't compute as fast, the entire matrix is calculated in
less than half a minute
using VelocityDB.
Verify.exe console application for verifying your data
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using VelocityDb;
using VelocityDb.Session;
namespace Verify
{
class Verify
{
static int Main(string[] args)
{
if (args.Length == 0)
{
System.Console.WriteLine("ERROR, no boot path specified. Restart Verify and add bootup database path as a command line parameter");
return 1;
}
int ct = 0;
try
{
using (SessionNoServer session = new SessionNoServer(args[0]))
{
DataCache.MaximumMemoryUse = 5000000000; // 5 GB, set this to what fits your case
session.BeginRead();
List<Database> dbList = session.OpenAllDatabases();
foreach (Database db in dbList)
foreach (Page page in db)
foreach (IOptimizedPersistable iPers in page)
{
object obj = iPers.WrappedObject;
++ct;
if (iPers.WrappedObject is IOptimizedPersistable)
{
UInt64 id = iPers.Id;
OptimizedPersistable pObj = iPers as OptimizedPersistable;
if (pObj != null)
{
pObj.LoadFields();
foreach (OptimizedPersistable fObj in pObj.OptimizedPersistableFieldValues())
{
fObj.LoadFields();
}
foreach (object value in pObj.GetFieldValues())
{
WeakIOptimizedPersistableReferenceBase weakRef = value as WeakIOptimizedPersistableReferenceBase;
if (weakRef != null)
if (session.Open(weakRef.Id) == null)
throw new UnexpectedException("WeakRefence object is null");
}
}
}
else if (obj is string)
continue;
else if (obj is Array)
continue;
IEnumerable anEnum = obj as IEnumerable;
if (anEnum != null)
foreach (object o in anEnum)
{
}
}
session.Commit();
}
Console.WriteLine("OK, verfied " + ct + " objects");
return 0;
}
catch (Exception ex)
{
Console.WriteLine("FAILED, verfied " + ct + " objects");
Console.WriteLine(ex.ToString());
return -1;
}
}
}
}
VelocityDbBrowser
Shows how to display persistent objects using an asp TreeView control. We are making the source code public so that you can help us improve the browser. Suggestions are welcome.
Text Indexer
This is a mini web crawler that grabs the text from selected web sites and shows which words are used and how frequently. I tried to use teqniques as described in a
paper by the Google founders. Did I do it right? Help me out!
The TextIndexer has been extended to also indexing local text files. We downloaded some free complete books from Top 100 - Project Gutenberg
Baseball statistics
This sample applications imports Baseball statistics data from csv files provided by Sean Lahman
NUnit tests
We are including some NUnit tests. These tests should further help explaining
how use the VelocityDb API. New NUnit tests are welcome! The NUnit GUI driver is awesome!
Issue Tracker
There are some good bug tracking software out there but we needed a more complete sample application so we build my own issue (bug) tracking system. Please help us improve this application so that it feels more complete.
This application is now included in the sample solution provided with the download of VelocityDB. A live demo of this application is available here.
Please help
By working together we can improve the samples. We develop using git as a source control tool. We will setup a repository on GitHub or a similar site until then please email us suggestions and C# sample code. Alternativly, you can use the Isuue tracker and open an issue describing an improvement or a bug. You can attach files to an issue.
Email to: Samples@VelocityDB.com
VelocityGraph Sample Applications
SupplierTracking
This sample shows one way to solve problem descibed here
// This sample shows one way to solve problem descibed in http://stackoverflow.com/questions/28060104/recursive-query-with-sub-graph-aggregation-arbitrary-depth
using Frontenac.Blueprints;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VelocityDb;
using VelocityDb.Session;
using VelocityGraph;
namespace SupplierTracking
{
class SupplierTracking
{
static readonly string s_systemDir = "SupplierTracking"; // appended to SessionBase.BaseDatabasePath
static readonly string s_licenseDbFile = "c:/4.odb";
static int Main(string[] args)
{
DataCache.MaximumMemoryUse = 10000000000; // 10 GB, set this to what fits your case
SupplierTracking supplierTracking = new SupplierTracking();
using (SessionNoServer session = new SessionNoServer(s_systemDir, 5000, false, true))
{
if (Directory.Exists(session.SystemDirectory))
Directory.Delete(session.SystemDirectory, true); // remove systemDir from prior runs and all its databases.
Directory.CreateDirectory(session.SystemDirectory);
File.Copy(s_licenseDbFile, Path.Combine(session.SystemDirectory, "4.odb"));
session.BeginUpdate();
Graph g = new Graph(session);
session.Persist(g);
// SCHEMA
VertexType warehouseVertexType = g.NewVertexType("Warehouse");
VertexType supplierVertexType = g.NewVertexType("Supplier");
EdgeType supplierWarehouseEdgeType = g.NewEdgeType("Warehouse", true, supplierVertexType, warehouseVertexType);
EdgeType moveToS1EdgeType = g.NewEdgeType("MoveS1To", true, warehouseVertexType, warehouseVertexType);
EdgeType moveToS2EdgeType = g.NewEdgeType("MoveS2To", true, warehouseVertexType, warehouseVertexType);
EdgeType moveToS3EdgeType = g.NewEdgeType("MoveS3To", true, warehouseVertexType, warehouseVertexType);
PropertyType supplierNameProperty = supplierVertexType.NewProperty("name", DataType.String, PropertyKind.NotIndexed);
PropertyType wareHouseNameProperty = warehouseVertexType.NewProperty("name", DataType.String, PropertyKind.NotIndexed);
PropertyType howManyS1Property = moveToS1EdgeType.NewProperty("howMany", DataType.Integer, PropertyKind.NotIndexed);
PropertyType howManyS2Property = moveToS2EdgeType.NewProperty("howMany", DataType.Integer, PropertyKind.NotIndexed);
PropertyType howManyS3Property = moveToS3EdgeType.NewProperty("howMany", DataType.Integer, PropertyKind.NotIndexed);
Vertex supplier1 = supplierVertexType.NewVertex();
supplier1.SetProperty(supplierNameProperty, "S1");
Vertex supplier2 = supplierVertexType.NewVertex();
supplier2.SetProperty(supplierNameProperty, "S2");
Vertex supplier3 = supplierVertexType.NewVertex();
supplier3.SetProperty(supplierNameProperty, "S3");
Vertex wareHouse1Supplier1 = warehouseVertexType.NewVertex();
supplier1.AddEdge(supplierWarehouseEdgeType, wareHouse1Supplier1);
wareHouse1Supplier1.SetProperty(wareHouseNameProperty, "A01");
Vertex wareHouse2Supplier1 = warehouseVertexType.NewVertex();
supplier1.AddEdge(supplierWarehouseEdgeType, wareHouse2Supplier1);
wareHouse2Supplier1.SetProperty(wareHouseNameProperty, "A02");
Vertex wareHouse3Supplier1 = warehouseVertexType.NewVertex();
supplier1.AddEdge(supplierWarehouseEdgeType, wareHouse3Supplier1);
wareHouse3Supplier1.SetProperty(wareHouseNameProperty, "A05");
Vertex wareHouse4Supplier1 = warehouseVertexType.NewVertex();
supplier1.AddEdge(supplierWarehouseEdgeType, wareHouse4Supplier1);
wareHouse4Supplier1.SetProperty(wareHouseNameProperty, "A06");
Vertex wareHouse1Supplier2 = warehouseVertexType.NewVertex();
supplier2.AddEdge(supplierWarehouseEdgeType, wareHouse1Supplier2);
wareHouse1Supplier2.SetProperty(wareHouseNameProperty, "A03");
Vertex wareHouse2Supplier2 = warehouseVertexType.NewVertex();
supplier2.AddEdge(supplierWarehouseEdgeType, wareHouse2Supplier2);
wareHouse2Supplier2.SetProperty(wareHouseNameProperty, "A07");
Vertex wareHouse1Supplier3 = warehouseVertexType.NewVertex();
supplier3.AddEdge(supplierWarehouseEdgeType, wareHouse1Supplier3);
wareHouse1Supplier3.SetProperty(wareHouseNameProperty, "A04");
Vertex wareHouse2Supplier3 = warehouseVertexType.NewVertex();
supplier3.AddEdge(supplierWarehouseEdgeType, wareHouse2Supplier3);
wareHouse2Supplier3.SetProperty(wareHouseNameProperty, "A08");
Vertex wareHouseB1 = warehouseVertexType.NewVertex();
wareHouseB1.SetProperty(wareHouseNameProperty, "B01");
Vertex wareHouseB2 = warehouseVertexType.NewVertex();
wareHouseB2.SetProperty(wareHouseNameProperty, "B02");
Vertex wareHouseB3 = warehouseVertexType.NewVertex();
wareHouseB3.SetProperty(wareHouseNameProperty, "B03");
Vertex wareHouseB4 = warehouseVertexType.NewVertex();
wareHouseB4.SetProperty(wareHouseNameProperty, "B04");
Vertex wareHouseC1 = warehouseVertexType.NewVertex();
wareHouseC1.SetProperty(wareHouseNameProperty, "C01");
Vertex wareHouseC2 = warehouseVertexType.NewVertex();
wareHouseC2.SetProperty(wareHouseNameProperty, "C02");
Vertex wareHouseD1 = warehouseVertexType.NewVertex();
wareHouseD1.SetProperty(wareHouseNameProperty, "D01");
Edge moveA1toB1 = wareHouse1Supplier1.AddEdge(moveToS1EdgeType, wareHouseB1);
moveA1toB1.SetProperty(howManyS1Property, 750);
Edge moveA2toB1 = wareHouse2Supplier1.AddEdge(moveToS1EdgeType, wareHouseB1);
moveA2toB1.SetProperty(howManyS1Property, 500);
Edge moveA3toB2 = wareHouse1Supplier2.AddEdge(moveToS2EdgeType, wareHouseB2);
moveA3toB2.SetProperty(howManyS2Property, 750);
Edge moveA4toB2 = wareHouse1Supplier3.AddEdge(moveToS3EdgeType, wareHouseB2);
moveA4toB2.SetProperty(howManyS3Property, 500);
Edge moveA5toB3 = wareHouse3Supplier1.AddEdge(moveToS1EdgeType, wareHouseB3);
moveA5toB3.SetProperty(howManyS1Property, 100);
Edge moveA6toB3 = wareHouse4Supplier1.AddEdge(moveToS1EdgeType, wareHouseB3);
moveA6toB3.SetProperty(howManyS1Property, 200);
Edge moveA7toB4 = wareHouse2Supplier2.AddEdge(moveToS2EdgeType, wareHouseB4);
moveA7toB4.SetProperty(howManyS2Property, 50);
Edge moveA8toB4 = wareHouse2Supplier3.AddEdge(moveToS3EdgeType, wareHouseB4);
moveA8toB4.SetProperty(howManyS3Property, 450);
Edge moveB1toC1 = wareHouseB1.AddEdge(moveToS1EdgeType, wareHouseC1);
moveB1toC1.SetProperty(howManyS1Property, 400);
Edge moveS2B2toC1 = wareHouseB2.AddEdge(moveToS2EdgeType, wareHouseC1);
moveS2B2toC1.SetProperty(howManyS2Property, 360);
Edge moveS3B2toC1 = wareHouseB2.AddEdge(moveToS3EdgeType, wareHouseC1);
moveS3B2toC1.SetProperty(howManyS3Property, 240);
Edge moveS1B3toC2 = wareHouseB3.AddEdge(moveToS1EdgeType, wareHouseC2);
moveS1B3toC2.SetProperty(howManyS1Property, 100);
Edge moveS2B4toC2 = wareHouseB4.AddEdge(moveToS2EdgeType, wareHouseC2);
moveS2B4toC2.SetProperty(howManyS2Property, 20);
Edge moveS3B4toC2 = wareHouseB4.AddEdge(moveToS3EdgeType, wareHouseC2);
moveS3B4toC2.SetProperty(howManyS3Property, 180);
Edge moveS1C1toD1 = wareHouseC1.AddEdge(moveToS1EdgeType, wareHouseD1);
moveS1C1toD1.SetProperty(howManyS1Property, 200);
Edge moveS2C1toD1 = wareHouseC1.AddEdge(moveToS2EdgeType, wareHouseD1);
moveS2C1toD1.SetProperty(howManyS2Property, 180);
Edge moveS3C1toD1 = wareHouseC1.AddEdge(moveToS3EdgeType, wareHouseD1);
moveS3C1toD1.SetProperty(howManyS3Property, 120);
Edge moveS1C2toD1 = wareHouseC2.AddEdge(moveToS1EdgeType, wareHouseD1);
moveS1C2toD1.SetProperty(howManyS1Property, 67);
Edge moveS2C2toD1 = wareHouseC2.AddEdge(moveToS2EdgeType, wareHouseD1);
moveS2C2toD1.SetProperty(howManyS2Property, 13);
Edge moveS3C2toD1 = wareHouseC2.AddEdge(moveToS3EdgeType, wareHouseD1);
moveS3C2toD1.SetProperty(howManyS3Property, 120);
Console.WriteLine("Supplier 1 to Warehouse D total: " + supplierTracking.CalculateTotalTo(supplier1, supplierWarehouseEdgeType, moveToS1EdgeType, howManyS1Property, wareHouseD1));
Console.WriteLine("Supplier 2 to Warehouse D total: " + supplierTracking.CalculateTotalTo(supplier2, supplierWarehouseEdgeType, moveToS2EdgeType, howManyS2Property, wareHouseD1));
Console.WriteLine("Supplier 3 to Warehouse D total: " + supplierTracking.CalculateTotalTo(supplier3, supplierWarehouseEdgeType, moveToS3EdgeType, howManyS3Property, wareHouseD1));
g.ExportToGraphJson("c:/SupplierTrackingExportToGraphJson.json");
Graph g2 = new Graph(session);
session.Persist(g2);
g2.ImportGraphJson("c:/SupplierTrackingExportToGraphJson.json");
session.Commit();
return 0;
}
}
int CalculateTotalTo(Vertex supplier, EdgeType supplierWarehouseEdgeType, EdgeType moveToEdgeType, PropertyType howManyProperty, Vertex toVertex)
{
int total = 0;
HashSet<Vertex> excludeSet = new HashSet<Vertex>();
foreach (IEdge wareHouseEdge in supplier.GetEdges(supplierWarehouseEdgeType, Direction.Out))
{
Vertex supplierWareHouse = (Vertex)wareHouseEdge.GetVertex(Direction.In);
var allPaths = supplierWareHouse.Traverse(toVertex, moveToEdgeType, 10, true, null, excludeSet);
foreach (List<Edge> path in allPaths)
{
if (path.Count > 0)
total += (int)path.Last().GetProperty(howManyProperty); // last because that is all we care about in this simplified sample
foreach (Edge edge in path)
{
excludeSet.Add(edge.Tail);
}
}
}
return total;
}
}
}
VelocityGraph
This sample is a preview of VelocityGraph, help us define the best possible graph api! The start of this api is inspired by Sparksee,
the sample here mimics what the Sparksee sample is doing. Unlike Sparksee, which is a C++/C implemented api,
VelocityGraph is all implemented in C# and enable any type of Element values. VelocityGraph is provided as open source on GitHub, https://github.com/VelocityDB/VelocityDB/tree/master/VelocityGraph.
and implements the graph API Blueprints standard interfaces as provided in Frontenac Blueprints.
Anyone is welcome to contribute! VelocityGraph is built on top of VelocityDB.
You will need a VelocityDB license to use VelocityGraph.
using System;
using System.IO;
using System.Linq;
using VelocityDb.Session;
using VelocityGraph;
namespace VelocityGraphSample
{
using Frontenac.Blueprints;
using System.Collections.Generic;
class VelocityGraphSample
{
static readonly string systemDir = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
"VelocityDB" + Path.DirectorySeparatorChar + "Databases" + Path.DirectorySeparatorChar + "VelocityGraphSample");
static void Main(string[] args)
{
if (Directory.Exists(systemDir))
Directory.Delete(systemDir, true); // remove systemDir from prior runs and all its databases.
using (ServerClientSession session = new ServerClientSession(systemDir, System.Net.Dns.GetHostName()))
{
session.BeginUpdate();
Graph g = new Graph(session);
session.Persist(g);
// SCHEMA
// Add a node type for the movies, with a unique identifier and two indexed Propertys
VertexType movieType = g.NewVertexType("MOVIE");
PropertyType movieTitleType = g.NewVertexProperty(movieType, "TITLE", DataType.String, PropertyKind.Indexed);
PropertyType movieYearType = g.NewVertexProperty(movieType, "YEAR", DataType.Integer, PropertyKind.Indexed);
// Add a node type for the people, with a unique identifier and an indexed Property
VertexType peopleType = g.NewVertexType("PEOPLE");
PropertyType peopleNameType = g.NewVertexProperty(peopleType, "NAME", DataType.String, PropertyKind.Indexed);
// Add an undirected edge type with a Property for the cast of a movie
EdgeType castType = g.NewEdgeType("CAST", false);
PropertyType castCharacterType = g.NewEdgeProperty(castType, "CHARACTER", DataType.String, PropertyKind.Indexed);
// Add a directed edge type restricted to go from people to movie for the director of a movie
EdgeType directsType = g.NewEdgeType("DIRECTS", true, peopleType, movieType);
// DATA
// Add some MOVIE nodes
Vertex mLostInTranslation = movieType.NewVertex();
mLostInTranslation.SetProperty(movieTitleType, "Lost in Translation");
mLostInTranslation.SetProperty(movieYearType, (int)2003);
Vertex mVickyCB = movieType.NewVertex();
mVickyCB.SetProperty(movieTitleType, "Vicky Cristina Barcelona");
mVickyCB.SetProperty(movieYearType, (int)2008);
Vertex mManhattan = movieType.NewVertex();
mManhattan.SetProperty(movieTitleType, "Manhattan");
mManhattan.SetProperty(movieYearType, (int)1979);
// Add some PEOPLE nodes
Vertex pScarlett = peopleType.NewVertex();
pScarlett.SetProperty(peopleNameType, "Scarlett Johansson");
Vertex pBill = peopleType.NewVertex();
pBill.SetProperty(peopleNameType, "Bill Murray");
Vertex pSofia = peopleType.NewVertex();
pSofia.SetProperty(peopleNameType, "Sofia Coppola");
Vertex pWoody = peopleType.NewVertex();
pWoody.SetProperty(peopleNameType, "Woody Allen");
Vertex pPenelope = peopleType.NewVertex();
pPenelope.SetProperty(peopleNameType, "Penélope Cruz");
Vertex pDiane = peopleType.NewVertex();
pDiane.SetProperty(peopleNameType, "Diane Keaton");
// Add some CAST edges
Edge anEdge;
anEdge = g.NewEdge(castType, mLostInTranslation, pScarlett);
anEdge.SetProperty(castCharacterType, "Charlotte");
anEdge = g.NewEdge(castType, mLostInTranslation, pBill);
anEdge.SetProperty(castCharacterType, "Bob Harris");
anEdge = g.NewEdge(castType, mVickyCB, pScarlett);
anEdge.SetProperty(castCharacterType, "Cristina");
anEdge = g.NewEdge(castType, mVickyCB, pPenelope);
anEdge.SetProperty(castCharacterType, "Maria Elena");
anEdge = g.NewEdge(castType, mManhattan, pDiane);
anEdge.SetProperty(castCharacterType, "Mary");
anEdge = g.NewEdge(castType, mManhattan, pWoody);
anEdge.SetProperty(castCharacterType, "Isaac");
// Add some DIRECTS edges
anEdge = g.NewEdge(directsType, pSofia, mLostInTranslation);
anEdge = g.NewEdge(directsType, pWoody, mVickyCB);
anEdge = g.NewEdge(directsType, pWoody, mManhattan);
// QUERIES
// Get the movies directed by Woody Allen
Dictionary<Vertex, HashSet<Edge>> directedByWoody = pWoody.Traverse(directsType, Direction.Out);
// Get the cast of the movies directed by Woody Allen
Dictionary<Vertex, HashSet<Edge>> castDirectedByWoody = g.Traverse(directedByWoody.Keys.ToArray(), castType, Direction.Both);
// Get the movies directed by Sofia Coppola
Dictionary<Vertex, HashSet<Edge>> directedBySofia = pSofia.Traverse(directsType, Direction.Out);
// Get the cast of the movies directed by Sofia Coppola
Dictionary<Vertex, HashSet<Edge>> castDirectedBySofia = g.Traverse(directedBySofia.Keys.ToArray(), castType, Direction.Both);
// We want to know the people that acted in movies directed by Woody AND in movies directed by Sofia.
IEnumerable<Vertex> castFromBoth = castDirectedByWoody.Keys.Intersect(castDirectedBySofia.Keys);
// Say hello to the people found
foreach (Vertex person in castFromBoth)
{
object value = person.GetProperty(peopleNameType);
System.Console.WriteLine("Hello " + value);
}
var billM = g.Traverse(directedBySofia.Keys.ToArray(), castType, Direction.Both).Keys.Where(vertex => vertex.GetProperty(peopleNameType).Equals("Bill Murray"));
// Say hello to Bill Murray
foreach (Vertex person in billM)
{
object value = person.GetProperty(peopleNameType);
System.Console.WriteLine("Hello " + value);
}
session.Commit();
}
using (ServerClientSession session = new ServerClientSession(systemDir, System.Net.Dns.GetHostName()))
{
session.BeginRead();
Graph g = Graph.Open(session);
VertexType movieType = g.FindVertexType("MOVIE");
PropertyType movieTitleProperty = g.FindVertexProperty(movieType, "TITLE");
Vertex obj = g.FindVertex(movieTitleProperty, "Manhattan");
session.Commit();
}
}
}
}
Facebook Graph
/*
Social graph test
http://odysseas.calit2.uci.edu/doku.php/public:online_social_networks#facebook_social_graph_-_breadth_first_search
Contains a set of unique users on Facebook, and all the userids of their friends. Can be used as a good example for finding shortest path queries.
queries:
- Find Shortest path between two given user ids
- Get all the paths between two user ids
- Get the number of unique 2nd level friends a given user has (friends of my friends)
- Get the top 10 users with most friends
*/
using Frontenac.Blueprints;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using VelocityDb;
using VelocityDb.Session;
using VelocityGraph;
namespace FacebookGraph
{
class FacebookGraph
{
static readonly string systemDir = "FacebookGraph";
static readonly string inputData = "D:/bfs-28-socialgraph-release-corrected"; // change if you need to, download dataset from http://www.VelocityDB.com/Public/bfs-28-socialgraph-release-corrected.zip (and uncompress with 7-zip http://www.7-zip.org/)
//static readonly string inputData = "D:\\bfs-28-socialgraph-release";// change if you need to, download dataset from http://odysseas.calit2.uci.edu/doku.php/public:online_social_networks#facebook_social_graph_-_breadth_first_search
static readonly string licenseDbFile = "D:/4.odb";
enum Gender { Male, Female, Unknown };
static void Main(string[] args)
{
DataCache.MaximumMemoryUse = 27000000000; // 27 GB, set this to what fits your case
FacebookGraph facebookGraph = new FacebookGraph();
//SessionBase.BaseDatabasePath = "d:/Databases";
bool import = args.Length > 0 && args[0].ToLower() == "-import";
bool dirExist = Directory.Exists(Path.Combine(SessionBase.BaseDatabasePath, systemDir));
if (import || !dirExist)
facebookGraph.ingestData();
facebookGraph.doQueries();
}
public void ingestData()
{
if (Directory.Exists(Path.Combine(SessionBase.BaseDatabasePath, systemDir)))
Directory.Delete(Path.Combine(SessionBase.BaseDatabasePath, systemDir), true); // remove systemDir from prior runs and all its databases.
Directory.CreateDirectory(Path.Combine(SessionBase.BaseDatabasePath, systemDir));
File.Copy(licenseDbFile, Path.Combine(SessionBase.BaseDatabasePath, systemDir, "4.odb"));
using (SessionNoServer session = new SessionNoServer(systemDir, false, 5000, false, true))
{
session.BeginUpdate();
session.DefaultDatabaseLocation().CompressPages = false;
Graph g = new Graph(session);
session.Persist(g);
// SCHEMA
VertexType userType = g.NewVertexType("User");
EdgeType friendEdgeType = g.NewEdgeType("Friend", true, userType, userType);
PropertyType countryProperty = userType.NewProperty("country", DataType.String, PropertyKind.NotIndexed);
PropertyType incomeProperty = userType.NewProperty("income", DataType.Long, PropertyKind.NotIndexed);
PropertyType friendshipStartProperty = friendEdgeType.NewProperty("start", DataType.DateTime, PropertyKind.NotIndexed);
// DATA
int lineNumber = 0;
long fiendsCt = 0;
int stop = (int)Math.Pow(2, 26); // make sure to create enough of these
for (int i = 1; i < stop; i++)
userType.NewVertex();
session.Commit();
session.BeginUpdate();
foreach (string line in File.ReadLines(inputData))
{
if (++lineNumber % 10000 == 0)
Console.WriteLine("Parsing user " + lineNumber + ", friends total: " + fiendsCt + " at " + DateTime.Now);
string[] fields = line.Split(' ');
Vertex aUser = null;
foreach (string s in fields)
{
if (s.Length > 0)
{
if (aUser == null)
aUser = new Vertex(g, userType, int.Parse(s));
else
{
++fiendsCt;
Vertex aFriend = new Vertex(g, userType, int.Parse(s));
if (fiendsCt % 2 == 0)
aFriend.SetProperty(countryProperty, "Sweden"); // just some random stuff
else
aFriend.SetProperty(incomeProperty, fiendsCt); // just some random stuff
Edge edge = friendEdgeType.NewEdge(aUser, aFriend);
if (fiendsCt % 2 == 0)
edge.SetProperty(friendshipStartProperty, DateTime.Now);
}
}
}
if (DataCache.MaximumMemoryUse >= 27000000000)
{
if (lineNumber >= 120000) // remove this condition if you have time to wait a while...
break;
}
else if (lineNumber >= 60000)
break;
}
Console.WriteLine("Done importing " + lineNumber + " users with " + fiendsCt + " friends");
session.Commit();
}
}
// Queries
public void doQueries()
{
using (SessionNoServer session = new SessionNoServer(systemDir, false))
{
session.BeginRead();
Graph g = Graph.Open(session); // it takes a while to open graph fresh from databases
VertexType userType = g.FindVertexType("User");
EdgeType friendEdgeType = g.FindEdgeType("Friend");
PropertyType countryProperty = userType.FindProperty("country");
PropertyType incomeProperty = userType.FindProperty("income");
PropertyType friendshipStartProperty = friendEdgeType.FindProperty("start");
Vertex someUser = userType.GetVertex(1);
Vertex someUser2 = userType.GetVertex(12282);
var someUserFriends = from Edge e in someUser.GetEdges(friendEdgeType, Direction.Out)
select e.Head;
HashSet<Edge> edges = new HashSet<Edge>();
Edge edge = (Edge)someUser.GetEdges(friendEdgeType, Direction.Out).Skip(1).First();
edges.Add(edge);
// Find Shortest path between two given user ids
List<List<Edge>> path = someUser.Traverse(someUser2, friendEdgeType, 10, false);
Debug.Assert(path.Count > 0);
var path2 = someUser.Traverse(userType.GetVertex(41), friendEdgeType, 10, false);
HashSet<Vertex> vertices = new HashSet<Vertex>();
vertices.Add(someUser2);
var path3 = someUser.Traverse(userType.GetVertex(2876), friendEdgeType, 10, false, vertices); // path must include vertices
var path3b = someUser.Traverse(userType.GetVertex(2876), friendEdgeType, 10, false, null, vertices); // path must NOT include vertices
var path3c = someUser.Traverse(userType.GetVertex(2876), friendEdgeType, 10, false, null, null, edges); // path must include edges
var path3d = someUser.Traverse(userType.GetVertex(2876), friendEdgeType, 10, false, null, null, null, edges); // path must NOT include edges
HashSet<PropertyType> vertexPropertyTypes = new HashSet<PropertyType>();
vertexPropertyTypes.Add(incomeProperty);
vertexPropertyTypes.Add(countryProperty);
var path3e = someUser.Traverse(userType.GetVertex(2876), friendEdgeType, 10, false, null, null, null, edges, vertexPropertyTypes); // path must NOT include edges and at least one vertex in path must have property in propertyTypes
var path3f = someUser.Traverse(userType.GetVertex(2876), friendEdgeType, 10, false, null, null, null, edges, null, vertexPropertyTypes); // path must NOT include edges and no vertex in path must have any property in propertyTypes
HashSet<PropertyType> edgePropertyTypes = new HashSet<PropertyType>();
edgePropertyTypes.Add(friendshipStartProperty);
var path3g = someUser.Traverse(userType.GetVertex(2876), friendEdgeType, 10, false, null, null, null, edges, null, null, edgePropertyTypes);
var path3h = someUser.Traverse(userType.GetVertex(2876), friendEdgeType, 10, false, null, null, null, edges, null, null, null, edgePropertyTypes);
var path3i = someUser.Traverse(userType.GetVertex(2876), friendEdgeType, 10, false, null, null, null, edges, null, null, null, null, p => { object pv = p.GetProperty(countryProperty); return pv != null && pv.Equals("Sweden"); });
var path3j = someUser.Traverse(userType.GetVertex(2876), friendEdgeType, 10, false, null, null, null, edges, null, null, null, null, null, p => { DateTime? pv = (DateTime?)p.GetProperty(friendshipStartProperty); return pv != null && pv.Value.CompareTo(DateTime.Now) > 0; });
var path4 = someUser.Traverse(userType.GetVertex(2798), friendEdgeType, 10, false);
var path5 = someUser.Traverse(userType.GetVertex(175), friendEdgeType, 10, false);
var path6 = someUser.Traverse(userType.GetVertex(1531), friendEdgeType, 10, false);
var path7 = someUser.Traverse(userType.GetVertex(1537), friendEdgeType, 10, false);
Console.WriteLine();
// Get all the paths between two user ids
var path8 = someUser.Traverse(someUser2, friendEdgeType, 10, true);
path = someUser.Traverse(userType.GetVertex(41), friendEdgeType, 10, true);
// Get the number of unique 2nd level friends a given user has (friends of my friends)
var someUsers2ndLevelFriends = (from v in someUserFriends
from Edge e in v.GetEdges(friendEdgeType, Direction.Out)
select e.Head).Distinct();
Console.WriteLine("unique 2nd level friends a given user has");
int ct = 0;
foreach (Vertex v in someUsers2ndLevelFriends)
{
if (++ct % 100 == 0)
Console.WriteLine("User id: " + v.VertexId);
}
Console.WriteLine("Some user has: " + ct + " 2nd level friends");
Console.WriteLine();
// Get the top 10 users with most friends
var top10mostFriends = from vertex in userType.GetTopNumberOfEdges(friendEdgeType, 10, Direction.Out)
select vertex;
Console.WriteLine("top 10 users with most friends");
foreach (Vertex v in top10mostFriends)
{
long count = v.GetNumberOfEdges(friendEdgeType, Direction.Out);
Console.WriteLine("User id: " + v.VertexId + "\t number of friends: " + count);
}
Console.WriteLine();
session.Commit();
}
}
}
}
Dating Recommendations
/*
Dating Recommendations
http://www.occamslab.com/petricek/data/
Dating site with ratings. Can be used to recommend other people a user might like.
17 million ratings, 168 000 profiles that are rated by 135 000 users.
Complex queries
- Given a user id, and based on the rated profiles, find other users who have rated similarly on the same profiles, and find other profiles to recommend based on what those other users have rated
- Get all female users with less than 50 ratings
- Get all male users with at least one 10 rating
- Get the first 10 male users who have rated at least 3 of the same profiles as the given user.
Statistics queries
- Get the 20 profiles with the most ratings
- Get the 20 best rated profiles regardless of gender
- Get the 20 best rated males
- Get the 20 best rated females
*/
using System;
using System.IO;
using System.Linq;
using VelocityDb.Session;
using VelocityGraph;
using Frontenac.Blueprints;
using System.Collections.Generic;
using VelocityDb;
namespace DatingRecommendations
{
class DatingRecommendations
{
static readonly string s_systemDir = SessionBase.BaseDatabasePath + "/DatingRecommendations";
static readonly string s_inputDataDir = "D:/libimseti"; // change if you need to, download dataset from http://www.occamslab.com/petricek/data/
static readonly string s_licenseDbFile = "c:/4.odb";
static readonly int s_highestRating = 10;
enum Gender { Male, Female, Unknown };
static void Main(string[] args)
{
bool import = args.Length > 0 && args[0].ToLower() == "-import";
bool dirExist = Directory.Exists(s_systemDir);
if (import || !dirExist)
{
if (dirExist)
Directory.Delete(s_systemDir, true); // remove systemDir from prior runs and all its databases.
Directory.CreateDirectory(s_systemDir);
File.Copy(s_licenseDbFile, Path.Combine(s_systemDir, "4.odb"));
using (SessionNoServer session = new SessionNoServer(s_systemDir))
{
DataCache.MaximumMemoryUse = 12000000000; // 12 GB, set this to what fits your case
SessionBase.BTreeAddFastTransientBatchSize = 10; // reduces memory usage
Vertex[] ratingVertices = new Vertex[10];
session.BeginUpdate();
session.DefaultDatabaseLocation().CompressPages = PageInfo.compressionKind.LZ4;
Graph g = new Graph(session);
session.Persist(g);
// SCHEMA
VertexType userType = g.NewVertexType("User");
PropertyType genderType = userType.NewProperty("Gender", DataType.Integer, PropertyKind.Indexed);
VertexType ratingType = g.NewVertexType("Rating");
PropertyType ratingValuePropertyType = ratingType.NewProperty("RatingValue", DataType.Integer, PropertyKind.Indexed);
EdgeType ratingEdgeType = g.NewEdgeType("UserToRating", true, userType, ratingType);
EdgeType ratingOfType = g.NewEdgeType("RatingOf", false, userType, userType);
PropertyType ratingEdgePropertyType = ratingOfType.NewProperty("Rating", DataType.Integer, PropertyKind.Indexed);
// DATA
using (FileStream stream = File.OpenRead(System.IO.Path.Combine(s_inputDataDir, "gender.dat")))
{
using (StreamReader file = new System.IO.StreamReader(stream))
{
string line;
int lineNumber = 0;
while ((line = file.ReadLine()) != null)
{
lineNumber++;
string[] fields = line.Split(',');
Vertex aUser = userType.NewVertex();
aUser.SetProperty(genderType, (int)fields[1][0] == 'M' ? Gender.Male : fields[1][0] == 'F' ? Gender.Female : Gender.Unknown);
}
Console.WriteLine("Done importing " + lineNumber + " users");
}
}
using (FileStream stream = File.OpenRead(System.IO.Path.Combine(s_inputDataDir, "ratings.dat")))
{
using (StreamReader file = new System.IO.StreamReader(stream))
{
string line;
int lineNumber = 0;
Vertex rater = null;
int raterId;
int priorRaterId = -1;
while ((line = file.ReadLine()) != null)
{
lineNumber++;
if (lineNumber % 1000000 == 0)
Console.WriteLine("Parsing rating # " + lineNumber);
string[] fields = line.Split(',');
raterId = int.Parse(fields[0]);
if (raterId != priorRaterId)
rater = userType.GetVertex(raterId);
priorRaterId = raterId;
int ratedId = int.Parse(fields[1]);
int rating = int.Parse(fields[2]);
Vertex ratingVertex = ratingVertices[rating - 1];
if (ratingVertex == null)
{
ratingVertex = ratingType.NewVertex();
ratingVertex.SetProperty(ratingValuePropertyType, rating);
ratingVertices[rating - 1] = ratingVertex;
}
Vertex rated = userType.GetVertex(ratedId);
Edge aRatingOf = ratingOfType.NewEdge(rater, rated);
aRatingOf.SetProperty(ratingEdgePropertyType, rating);
Edge userRating = ratingEdgeType.NewEdge(rated, ratingVertex);
}
Console.WriteLine("Done importing " + lineNumber + " ratings");
}
}
session.Commit();
}
}
// Query
using (SessionNoServer session = new SessionNoServer(s_systemDir))
{
session.BeginRead();
Graph g = Graph.Open(session);
VertexType userType = g.FindVertexType("User");
PropertyType genderType = userType.FindProperty("Gender");
VertexType ratingType = g.FindVertexType("Rating");
PropertyType ratingValuePropertyType = ratingType.FindProperty("RatingValue");
EdgeType ratingEdgeType = g.FindEdgeType("UserToRating");
EdgeType ratingOfType = g.FindEdgeType("RatingOf");
PropertyType ratingEdgePropertyType = ratingOfType.FindProperty("Rating");
// Complex queries
int ct = 0;
// Given a user id, and based on the rated profiles, find other users who have rated similarly on the same profiles, and find other profiles to recommend based on what those other users have rated
Vertex someUser = userType.GetVertex(1);
var similarRatings = (from Edge e in someUser.GetEdges(ratingOfType, Direction.Out)
from Edge edge in e.Head.GetEdges(ratingOfType, Direction.Out)
where someUser != edge.Head
where ((int)e.GetProperty(ratingEdgePropertyType) == (int)edge.GetProperty(ratingEdgePropertyType))
select edge.Tail).Distinct();
var someUserRated = from Edge e in someUser.GetEdges(ratingOfType, Direction.Out)
select e.Head;
var recommendedProfles = from v in similarRatings
from Edge e in v.GetEdges(ratingOfType, Direction.Out)
where someUserRated.Contains(e.Head) == false
select e.Head;
Console.WriteLine("Some user's rated profiles");
ct = 0;
foreach (Vertex v in someUserRated)
{
if (ct++ % 50 == 0) // don't print them all !
Console.WriteLine("User id: " + v.VertexId);
}
Console.WriteLine("Number of some user's rated profiles: " + ct);
Console.WriteLine("Given a user id, and based on the rated profiles, find other users who have rated similarly on the same profiles");
ct = 0;
foreach (Vertex v in similarRatings)
{
if (ct++ % 50 == 0) // don't print them all !
Console.WriteLine("User id: " + v.VertexId);
}
Console.WriteLine("Number of matching profiles: " + ct);
Console.WriteLine("Given a user id, and based on the rated profiles, find other users who have rated similarly on the same profiles, and find other profiles to recommend based on what those other users have rated");
ct = 0;
foreach (Vertex v in recommendedProfles)
{
if (ct++ % 5000 == 0) // don't print them all !
Console.WriteLine("User id: " + v.VertexId);
}
Console.WriteLine("Number of matching profiles: " + ct);
// Get all female users with less than 50 ratings
Console.WriteLine();
var females = from u in userType.GetVertices()
where ((Gender)u.GetProperty(genderType)) == Gender.Female
select u;
var femalesLess50Ratings = from f in females
where f.GetNumberOfEdges(ratingEdgeType, Direction.Out) < 50
select f;
Console.WriteLine("Female users with less than 50 ratings");
ct = 0;
foreach (Vertex f in femalesLess50Ratings)
{
long count = f.GetNumberOfEdges(ratingEdgeType, Direction.Out);
if (ct++ % 5000 == 0) // don't print them all !
Console.WriteLine("User id: " + f.VertexId + "\tnumber of ratings: " + count);
}
Console.WriteLine("Number of females with fewer than 50 ratings: " + ct);
Console.WriteLine();
// Get all male users with at least one 10 rating
Console.WriteLine();
var rated10vertex = (from v in ratingType.GetVertices()
where ((int)v.GetProperty(ratingValuePropertyType)) == 10
select v).First();
var rated10 = (from e in rated10vertex.GetEdges(ratingEdgeType, Direction.In)
select e.GetVertex(Direction.Out)).Distinct();
var rated10male = from Vertex v in rated10
where ((Gender)v.GetProperty(genderType)) == Gender.Male
select v;
Console.WriteLine("Males with at least one 10 rating");
ct = 0;
foreach (Vertex v in rated10male)
{
if (ct++ % 5000 == 0) // don't print them all !
Console.WriteLine("User id: " + v.VertexId);
}
Console.WriteLine("Number of males with at least one 10 rating: " + ct);
Console.WriteLine();
// Get the first 10 male users who have rated at least 3 of the same profiles as the given user.
Console.WriteLine("10 male users who have rated at least 3 of the same profiles as the given user");
var males = from u in userType.GetVertices()
where ((Gender)u.GetProperty(genderType)) == Gender.Male
select u;
var someUserHasRated = from Edge o in someUser.GetEdges(ratingOfType, Direction.Out)
select o.Head;
var first10withSame3ratedAs = from m in males
where (from Edge r in m.GetEdges(ratingOfType, Direction.Out) select r.Head).Intersect(someUserHasRated).ToArray().Length >= 3
select m;
ct = 0;
foreach (Vertex v in first10withSame3ratedAs)
{
if (++ct > 10)
break;
Console.WriteLine("User id: " + v.VertexId);
}
Console.WriteLine();
// Statistical queries
// Get the 20 profiles with the most ratings
var top20mostRatings = (from v in userType.GetVertices()
orderby v.GetNumberOfEdges(ratingEdgeType, Direction.Out) descending
select v).Take(20);
Console.WriteLine("20 profiles with the most ratings");
ct = 0;
foreach (Vertex v in top20mostRatings)
{
int count = (int)v.GetNumberOfEdges(ratingEdgeType, Direction.Out);
Console.WriteLine("User id: " + v.VertexId + "\tnumber of ratings: " + count);
}
Console.WriteLine();
var ratingsVertexEnum = from v in ratingType.GetVertices() orderby v.GetProperty(ratingValuePropertyType) descending select v;
Vertex rating10Vertex = ratingsVertexEnum.First();
// Get the 20 best rated profiles regardless of gender
var top = from u in userType.GetVertices()
let edgeCt = u.GetNumberOfEdges(ratingEdgeType, rating10Vertex, Direction.Out)
orderby edgeCt descending
select new { u, edgeCt };
Console.WriteLine("20 best rated profiles regardless of gender");
ct = 0;
foreach (var v in top)
{
if (++ct > 20)
break;
Console.WriteLine("User id: " + v.u.VertexId + "\t10 ratings: " + v.edgeCt);
}
Console.WriteLine();
// Get the 20 best rated males
Console.WriteLine("20 best rated male profiles");
var top20males = from u in userType.GetVertices()
where ((Gender)u.GetProperty(genderType)) == Gender.Male
let edgeCt = u.GetNumberOfEdges(ratingEdgeType, rating10Vertex, Direction.Out)
orderby edgeCt descending
select new { u, edgeCt };
ct = 0;
foreach (var v in top20males)
{
if (++ct > 20)
break;
Console.WriteLine("Male User id: " + v.u.VertexId + " \t10 ratings: " + v.edgeCt);
}
Console.WriteLine();
// Get the 20 best rated females
Console.WriteLine("20 best rated female profiles");
var top20females = from u in userType.GetVertices()
where ((Gender)u.GetProperty(genderType)) == Gender.Female
let edgeCt = u.GetNumberOfEdges(ratingEdgeType, rating10Vertex, Direction.Out)
orderby edgeCt descending
select new { u, edgeCt };
ct = 0;
foreach (var v in top20females)
{
if (++ct > 20)
break;
Console.WriteLine("Female User id: " + v.u.VertexId + "\t10 ratings: " + v.edgeCt);
}
session.Commit();
}
}
}
}