Introduction
Ever created a stellar class and then had to write subroutines to save and retrieve it? Ugh. I got tired of this, so I created the Saveable
class. You can extend this class through any class you've written using inheritance.
It uses JSON (JavaScript Object Notation) serialization (now built-into the .NET Framework 3.5 and Visual Studio 2008) to iterate through the members of a class, retrieve the data and save it to a file.
Wait!? You're using JSON for a database?! Yeah, that's right. JSON serialization is faster and creates smaller files than XML serialization while still maintaining human-readability. I know this was not the original purpose of JSON, but it works, and it works very well.
The example implementation I've included is a blog engine. WARNING: It's ultra-simple just to show off the features of Saveable(Of T)
. It would need a lot of work before putting it out in the real world. But it does include code for managing posts and comments. It also has code for performing ranked searches on the posts using RegularExpression
and LINQ
.
Using the Code
The core of my Saveable
class is the two methods: ToJSON
, and FromJSON
:
Shared Serializer As New Runtime.Serialization.Json.DataContractJsonSerializer(GetType(T))
Public Shared Function ToJSON(ByVal Obj As Object) As String
Dim tt As New IO.MemoryStream
Serializer.WriteObject(tt, Obj)
tt.Close()
Return System.Text.Encoding.ASCII.GetString(tt.ToArray)
End Function
Public Shared Function FromJSON(ByVal Data As String, ByVal Type As Type) As Object
If String.IsNullOrEmpty(Data) Then Return Nothing
Dim tt As New IO.MemoryStream(System.Text.Encoding.ASCII.GetBytes(Data))
Return Serializer.ReadObject(tt)
End Function
These methods convert your object to and from text.
To get started using the class, create your own class that inherits from Saveable(Of T)
, where T
is the type of your class. Then import System.Runtime.Serialization
and add a DataContract
attribute.
Imports System.Runtime.Serialization
Public Class BlogMessage : Inherits Saveable(Of BlogMessage)
End Class
Next, add whatever properties your class needs. The Saveable(Of T)
class already contains properties for ID as GUID
, DateCreated as Date
, and DateModified as Date
.
Imports System.Runtime.Serialization
<DataContract()> Public Class BlogMessage : Inherits Saveable(Of BlogMessage)
Dim _Title As String
<DataMember()> Public Property Title() As String
Get
Return _Title
End Get
Set(ByVal value As String)
_Title = value
End Set
End Property
Dim _message As String
<DataMember()> Public Property Message() As String
Get
Return _message
End Get
Set(ByVal value As String)
_message = value
End Set
End Property
End Class
Now, you can do the cool stuff:
Dim b as New BlogMessage With { .Title = "My New Post!", _
.Message = "This is the content for the post." }
b.Save()
The Save()
method creates a new ID
if necessary, sets the DateCreated
if blank, updates the DateUpdated
, serializes the object into text, and saves it to a *.js file--named after the ID, under a folder named after the object (BlogMessage
in this case) under the App_Data folder (i.e. ~/App_Data/BlogMessage/42dc0fb5-c516-4536-b273-6bbff8ed33ae.js).
Loading the object back into memory is just as easy:
Dim b as BlogMessage = BlogMessage.Load("42dc0fb5-c516-4536-b273-6bbff8ed33ae")
Response.Write(b.Message)
And now, take your class into high gear. I added another class BlogComment
, which also inherits from Saveable(Of T)
. Then I added some LINQ (which is just AWESOME, by the way):
Imports System.Runtime.Serialization
Imports System.Linq
<DataContract()> Public Class BlogMessage : Inherits Saveable(Of BlogMessage)
<DataMember(Name:="Comments")> Dim _comments As Generic.Dictionary_
(Of Guid, BlogComment)
Public ReadOnly Property Comments() As Generic.Dictionary(Of Guid, BlogComment)
Get
If _comments Is Nothing Then _comments = _
New Generic.Dictionary(Of Guid, BlogComment)
Return _comments
End Get
End Property
Dim _Title As String
<DataMember()> Public Property Title() As String
Get
Return _Title
End Get
Set(ByVal value As String)
_Title = value
End Set
End Property
Dim _message As String
<DataMember()> Public Property Message() As String
Get
Return _message
End Get
Set(ByVal value As String)
_message = value
End Set
End Property
Public Shared Function GetPostByTitle(ByVal Title As String) As BlogMessage
Dim o As Generic.IEnumerable(Of BlogMessage) = From b As BlogMessage In _
BlogMessage.GetAll Where b.Title.Equals_
(Title, StringComparison.OrdinalIgnoreCase) Take 1
If o.Count = 0 Then Return Nothing
Return o.First
End Function
Public Shared Function Search(ByVal Terms As String) As BlogMessage()
Dim r As New Regex("(" & Terms.Trim.Replace(" ", ")|(") & ")", _
RegexOptions.Singleline Or RegexOptions.IgnoreCase Or _
RegexOptions.Compiled)
Return (From b As BlogMessage In BlogMessage.GetAll Select b, k = _
b.Rank(r) Where k >= 0 Order By k Descending Select b).ToArray
End Function
Private Function Rank(ByVal r As Regex) As Double
Dim c As String = Title & vbNewLine & Message
Dim m As MatchCollection = r.Matches(c)
If m.Count = 0 Then Return -1
Return Aggregate dm As Match In m Into Sum(dm.Index / c.Length)
End Function
End Class
Points of Interest
JSON and LINQ are cool!
To Do: Learn more LINQ! It's awesome and incredibly powerful. Check out the examples here.