2. what we do
consulting training design debugging
who we are
Founded by top experts on Microsoft – Jeffrey Richter, Jeff Prosise, and John Robbins –
we pull out all the stops to help our customers achieve their goals through advanced
software-based consulting and training solutions.
how we do it Training
• On-site instructor-led training
Consulting & Debugging • Virtual instructor-led training
• Architecture, analysis, and design services • Devscovery conferences
• Full lifecycle custom software development
• Content creation Design
• Project management • User Experience Design
• Debugging & performance tuning • Visual & Content Design
• Video & Animation Production
consulting training design debugging wintellect.com
3. Agenda
• What is Sterling?
• Brief History
• Stated Goals
• Features
• Sterling vs. SQL CE
• Who is Using Sterling?
• Demo: Recipe Application
• Questions?
consulting training design debugging wintellect.com
4. What is Sterling?
“Sterling is a lightweight NoSQL object-oriented database for .Net 4.0, Silverlight
4 and 5, and Windows Phone 7 that works with your existing class structures.
Sterling supports full LINQ to Object queries over keys and indexes for fast
retrieval of information from large data sets.”
• Sterling is not a fully relational database
• Sterling is not a document database
• Sterling is not a transactional, large scale database
• Sterling focuses on specific serialization concerns
• Sterling is suitable for local caches
• Sterling is suitable for local lightweight data storage or a window of
data that synchronizes with a parent server
• Sterling is a very easy way to quickly persist existing classes, especially
with dynamic schemas
consulting training design debugging wintellect.com
5. Brief History
• Many customers were working with Silverlight 4 because of the ability
to have the out-of-browser (OOB) offline mode
• Found that existing serialization strategies tended to be shallow,
invasive, and lacked query capabilities
• Used various techniques such as synchronizing lists as individual items
and then providing a “keyed” index or view into the list
• Built first version of Sterling to abstract this and introduce concept of
both indexes and foreign keys to serialization
• Windows Phone 7 was released and Sterling filled the need for a local
database
• Was able to port over to run on Windows Phone 7 within hours
(mostly just needed to stub Silverlight 3 – Silverlight 4 differences)
• Popularity grew and requests came in for in-memory, .NET, etc.
versions, (1.5 release)
consulting training design debugging wintellect.com
6. Stated Goals
• Non-intrusive – don’t modify your classes or
derive from some base class just to be able to use
it.
• Lightweight – current DLL is < 100 kilobytes.
• Flexible – extensions for adding compression,
encryption, triggers, custom serializers, etc.
• Portable – same API in browser, on desktop/server
and in phone (possible Mono versions in the
pipeline)
consulting training design debugging wintellect.com
7. Features
• Recurses complex object graphs and handles cycle conditions
• Handles public properties and fields (including interface/abstract)
• Ability to suppress serialization of fields, properties, and types
• Flexible “is dirty” support to avoid saving full graph
• Driver-model allowing in-memory, isolated storage versions for phone
• Easy configuration – specify table type, key type, and how to resolve
the key or index
• “Save as” allows saving derived types to base class
• Full “foreign key” allowing child objects to serialize to separate tables
• Binary serialization for much smaller footprint
• Extensions for serialization, compression, encryption, etc.
• Trigger support
• Database backup and restore
• LINQ to Object queries on in-memory keys, indexes, “records”
consulting training design debugging wintellect.com
8. Sterling DB vs. SQL CE
Feature Sterling DB SQL CE
Database Backup
Database Create
Insert Many Items
Delete Items
Truncate Table
Search Substring
Search Key
Search Key w/ Joins
Search Non-Idx Col
Search Index
Serialize Full Graph
Dynamic Types
consulting training design debugging wintellect.com
9. Who is Using Sterling?
• HealthCaddy
• Sharp DropBox Client for .NET
(WP7 Library)
• Expense Report Tracker
• Horse Vaccine Tracker
• Stacks for Instapaper
• SmugSeven
• RunKeeper
• MyReiningScores
• Many more that you can read
about on the Sterling site
consulting training design debugging wintellect.com
10. demo
recipe application
consulting training design debugging wintellect.com
11. Define your Database
public class RecipeDatabase : BaseDatabaseInstance
{
protected override List<ITableDefinition> _RegisterTables()
{
return new List<ITableDefinition>();
}
/// this is optional, will default to full type name
public override string Name
{
get { return STERLING_RECIPES; }
}
}
consulting training design debugging wintellect.com
12. Define a “Table” and Key
This is provided in the base database class
Type of the “table”
CreateTableDefinition<IngredientModel, int>(i => i.Id)
Type of the key
Expression: given the “table” how do I get the key?
* Keys are stored in-memory for fast search & lookup
(100,000 records w/ Int32 key = 400,000 bytes, < 400Kb memory)
consulting training design debugging wintellect.com
13. Composite Keys
public static string GetCompositeKey(TestCompositeClass
testClass)
{
if (testClass == null) return string.Empty;
return string.Format("{0}-{1}-{2}-{3}", testClass.Key1,
testClass.Key2, testClass.Key3, testClass.Key4);
}
// method 1 uses a string
CreateTableDefinition<TestCompositeClass,string>(GetCompositeKey)
// method 2 uses a class to represent the key
// requires a custom serializer
CreateTableDefinition<TestCompositeClass,
TestCompositeKeyClass>(k=>
new TestCompositeKeyClass(k.Key1, k.Key2, k.Key3, k.Key4))
consulting training design debugging wintellect.com
14. Define an Index
CreateTableDefinition<FoodModel, int>(f => f.Id)
Extension method for tables
Type of the table
Type of the index
.WithIndex<FoodModel, string, int>
Type of the key
(IDX_FOOD_NAME, f => f.FoodName)
Expression: given table, how do I get index?
Name of the index
* Indexes, like keys, are stored in memory so choose wisely!
consulting training design debugging wintellect.com
15. Activating the Engine/Databases
_engine = new SterlingEngine();
// register custom serializers
_engine.SterlingDatabase.RegisterSerializer<TypeSerializer>();
// register any loggers (or use the default logger)
_logger = new
SterlingDefaultLogger(SterlingLogLevel.Information);
// activate the engine – now ready for your databases
_engine.Activate();
// here is a database registration
Database =
_engine.SterlingDatabase.RegisterDatabase<RecipeDatabase>();
consulting training design debugging wintellect.com
16. Drivers
Database =
_engine.SterlingDatabase.RegisterDatabase<RecipeDatabase>();
Database =
_engine.SterlingDatabase.RegisterDatabase<RecipeDatabase>(
new IsolatedStorageDriver());
Database =
_engine.SterlingDatabase.RegisterDatabase<RecipeDatabase>(
new MyCustomDriver());
consulting training design debugging wintellect.com
17. Serializers
// required for any keys that are not core value types
// required for any classes that are not easily de-serialized
// (i.e. no parameterless constructor, etc. – e.g. “Type” class)
public class TypeSerializer : BaseSerializer
{
public override bool CanSerialize(Type targetType)
{
return typeof (Type).IsAssignableFrom(targetType);
}
. . .
}
consulting training design debugging wintellect.com
18. Serializers (cont.)
public class TypeSerializer : BaseSerializer
{
public override void Serialize(object target, BinaryWriter
writer)
{
var type = target as Type;
. . .
writer.Write(type.AssemblyQualifiedName);
}
. . .
}
consulting training design debugging wintellect.com
19. Serializers (cont.)
public class TypeSerializer : BaseSerializer
{
public override object Deserialize(Type type, BinaryReader
reader)
{
return Type.GetType(reader.ReadString());
}
. . .
}
consulting training design debugging wintellect.com
20. Triggers
public class IdentityTrigger<T> : BaseSterlingTrigger<T,int>
where T: class, IBaseModel, new()
{
private static int _idx = 1;
public IdentityTrigger(ISterlingDatabaseInstance database)
{
// if a record exists, set it to the highest value plus 1
if (database.Query<T,int>().Any())
{
_idx = database.Query<T, int>().Max(key => key.Key) +
1;
}
}
}
consulting training design debugging wintellect.com
21. Triggers (cont.)
public override bool BeforeSave(T instance)
{
if (instance.Id < 1)
{
instance.Id = _idx++;
}
return true;
}
public override void AfterSave(T instance)
{
// set dirty flag?
return;
}
consulting training design debugging wintellect.com
22. Database Setup
// register trigger
database.RegisterTrigger(new
IdentityTrigger<FoodModel>(database));
// check for existing records
if (database.Query<CategoryModel, int>().Any()) return;
// truncate tables
database.Truncate(typeof (MeasureModel));
database.Truncate(typeof (FoodModel));
// save an entity (handles update and insert)
database.Save(measure);
database.Flush(); // ensure keys/indexes are persisted!
consulting training design debugging wintellect.com
23. Dynamic Tombstoning Support
var tombstone = new TombstoneModel {SyncType = typeof
(IRecipeViewModel)};
tombstone.State.Add(RECIPE_ID, _recipe.Id);
Tombstone.State.Add("ComplexType", MyComplexType);
database.Save(tombstone);
// handles recursion into sub-lists and dictionaries
// further recursion on types
// will not choke on cycles
// take a look at tests for examples
// TestCycle, TestEnum, TestInterfaceProperty, TestNestedInstance
consulting training design debugging wintellect.com
24. Queries
public IEnumerable<RecipeModel> Recipes
{
get Dual key handled by tuple
{
return
from r in
App.Database.Query<RecipeModel, int, string,
int>(RecipeDatabase.IDX_RECIPE_CATEGORYID_NAME)
where r.Index.Item1.Equals(CurrentCategory == null ?
0 : CurrentCategory.Id)
orderby r.Index.Item2
select new RecipeModel {Id = r.Key, Name =
r.Index.Item2};
}
} “Covered query” = no deserialization
consulting training design debugging wintellect.com
25. Queries (cont.)
get
{
if (string.IsNullOrEmpty(_foodText))
{
return Enumerable.Empty<FoodModel>();
}
var foodTextLower = _foodText.ToLower();
return from f in App.Database.Query<FoodModel, string,
int>(RecipeDatabase.IDX_FOOD_NAME)
where f.Index.ToLower().Contains(foodTextLower)
orderby f.Index
select new FoodModel {Id = f.Key, FoodName =
f.Index};
}
“Covered query” = no deserialization
consulting training design debugging wintellect.com
26. Queries (cont.)
get
{
return from m in App.Database.Query<MeasureModel, int>()
orderby m.LazyValue.Value.FullMeasure
Lazy value access will de-serialize
select m.LazyValue.Value;
}
Second access will retrieve cached value
consulting training design debugging wintellect.com
27. Compression/Encryption
public class ByteInterceptor : BaseSterlingByteInterceptor
{
override public byte[] Save(byte[] sourceStream)
{
var retVal = new byte[sourceStream.Length];
for (var x = 0; x < sourceStream.Length; x++)
{
retVal[x] = (byte)(sourceStream[x] ^ 0x80); // xor
}
return retVal;
}
override public byte[] Load(byte[] sourceStream)
{
var retVal = new byte[sourceStream.Length];
for (var x = 0; x < sourceStream.Length; x++)
{
retVal[x] = (byte)(sourceStream[x] ^ 0x80); // xor
}
return retVal;
}
}
consulting training design debugging wintellect.com
28. Compression/Encryption (cont.)
databaseInstance.RegisterInterceptor<ByteInterceptor>();
databaseInstance.RegisterInterceptor<ByteInterceptor2>();
// called in order of registration on save
// called in reverse order on load
// i.e. compression -> encrypt, then decrypt -> decompress
consulting training design debugging wintellect.com
29. Sterling Resources
• Full source, documentation, discussions, support:
http://sterling.codeplex.com/
• User’s Guide (your BEST guide is the unit tests):
http://www.sterlingdatabase.com/
• Telerik todolist “How-to” Application:
http://www.telerik.com/products/windows-
phone/getting-started/todolists.aspx
• My Blog:
http://csharperimage.jeremylikness.com/
(@JeremyLikness on Twitter)
consulting training design debugging wintellect.com
30. Questions?
Jeremy Likness
Project Manager, Senior Consultant
jlikness@wintellect.com
consulting training design debugging wintellect.com