mirror of
https://github.com/ClemensFischer/XAML-Map-Control.git
synced 2025-12-06 07:12:04 +01:00
- Added ImageFileCache and FileDbCache for WinRT - Improved TileImageLoader - Removed TileContainer, TileLayer can be added as MapBase child - Removed attached property MapPanel.ViewportPosition
983 lines
43 KiB
HTML
983 lines
43 KiB
HTML
<html>
|
|
|
|
<head>
|
|
<meta http-equiv="Content-Language" content="en-au">
|
|
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
|
<title>FileDb Overview</title>
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<b>
|
|
<p><font face="Arial" size="4" color="#0066CC">Overview</font></p>
|
|
</b>
|
|
<p><font face="Arial">FileDb is a simple database designed as a simple
|
|
local database solution for Xamarin Cross-Platform phone (Android, IOS, WinPhone)
|
|
or any .NET application. <u>FileDb is a No-SQL database</u>
|
|
meant for use as a local data store for applications.
|
|
Here are some important points about FileDb:</font></p>
|
|
|
|
<ul>
|
|
<li>
|
|
<font face="Arial">Stores one table per file, including its index</font></li>
|
|
<li>
|
|
<font face="Arial">Extremely Lightweight - less than 50K</font></li>
|
|
<li>
|
|
<font face="Arial">Supports field types Int, UInt, Bool, String, Byte,
|
|
Float, Double and DateTime and also arrays of the same
|
|
types</font></li>
|
|
<li>
|
|
<font face="Arial">Index supports a single Primary Key field (optional)</font></li>
|
|
<li>
|
|
<font face="Arial">Compiled versions for Windows Phone
|
|
RT/PCL,
|
|
.NET</font></li>
|
|
<li>
|
|
<font face="Arial">FileDb is VERY FAST</font></li>
|
|
<li>
|
|
<font face="Arial">FileDb is FREE to use in your applications</font></li>
|
|
<li>
|
|
<font face="Arial">Use with LINQ to Objects to achieve full relational
|
|
capability</font></li>
|
|
</ul>
|
|
|
|
<p><font face="Arial">FileDb was specifically designed to use only native
|
|
.NET data types so there would no need to translate
|
|
between database storage and the CLR data types.
|
|
So you can just as easily read/write a String[] field as
|
|
you would an Int field. Another feature is that a
|
|
database file created on any .NET platform will work on
|
|
any other. So you can create a database file on
|
|
your Windows machine and it can be used in a Silverlight
|
|
or Windows Phone app.</font></p>
|
|
|
|
<p><font color="#0066CC" face="Arial"><b>LINQ + FileDb gives you full
|
|
relational database capability</b></font></p>
|
|
<p><font face="Arial">Even though FileDb is a "flat-file" database, using
|
|
LINQ it becomes fully relational! LINQ
|
|
to Objects allows you to join Tables together just as
|
|
you would do in SQL. All of the power of LINQ is
|
|
available to you: Joins, Grouping, Sum - the lot.
|
|
(See
|
|
the examples below.)</font></p>
|
|
<p><font face="Arial">FileDb also has a built-in
|
|
query filter parser so you can write SQL-like
|
|
filter expressions to make filtering data easy, like
|
|
this:</font></p>
|
|
<blockquote>
|
|
<p><b>
|
|
<font color="#663300" face="Courier New" size="2">
|
|
string filter = "FirstName IN ('Cindy', 'John') AND Age > 32"</font></b></p>
|
|
</blockquote>
|
|
<p><font face="Arial">Use FileDb in your .NET and mobile
|
|
applications where you need a searchable, updatable
|
|
local database.</font><p>
|
|
<b><font face="Arial" color="#0066CC">Use FileDb with Xamarin cross-platform app
|
|
development</font></b><p><font face="Arial">Most phone apps only require a
|
|
simple database. By purchasing a source code license you can compile
|
|
FileDb into your IOS, Android and Windows Phone projects and use the same exact
|
|
data layer code for them all. This is much easier than using Sqlite
|
|
wrappers. With FileDb's built in encryption you can have everything you
|
|
need to have a secure data layer.</font></p>
|
|
<p>
|
|
<font color="#0066CC" face="Arial"><b>FileDb Database Overview</b></font></p>
|
|
|
|
<p><font face="Arial">FileDb is a simple database designed for use on any .NET platform such as Windows
|
|
Phone and Silverlight, but its also great for any .NET app where simple local
|
|
database storage is needed. For example, instead of using XML config files you
|
|
could use a FileDb database to store and retrieve application data much more
|
|
efficiently. FileDb allows only a single table per database file, so when we
|
|
talk about a FileDb database we really mean a single table with an index. The
|
|
index is stored in the file with the data, and allows an optional Primary Key.</font></p>
|
|
<p><font face="Arial">FileDb is NOT a relational database - it is NO-SLQ,
|
|
meaning you can't directly issue SQL commands for querying, adding or updating. However,
|
|
you CAN use LINQ with
|
|
FileDb to get full relational query capabilities. And FileDb does include an Expression Parser which parses SQL-like filter
|
|
expressions, which makes searching, updating and deleting very easy - see below for an example.</font></p>
|
|
<p><font face="Arial"><u>And FileDb supports using powerful Regular Expressions for
|
|
filtering.</u></font></p>
|
|
<p><font face="Arial"><u>FileDb supports AES encryption</u> at the record level. This
|
|
means the database schema is not encrypted (field names, etc.), but each record
|
|
is entirely encrypted. Encryption is "all or nothing", meaning it expects that
|
|
either all records are encrypted or all records are not encrypted. You turn
|
|
encryption on by passing an encryption key when opening the database.</font></p>
|
|
<u>
|
|
<p dir="ltr"><font face="Arial">FileDb is thread-safe for multithreading environments, so it can be accessed from
|
|
multiple threads at the same time without worrying about database corruption.</font></u></p>
|
|
<p><font face="Arial">FileDb databases can only be opened by a single
|
|
application. Any attempt to open the file when already open will fail.
|
|
This makes sense since its meant for use by a single application at a time
|
|
(FileDb is not meant as a multi-user database, such as SQL Server Express).<br>
|
|
</font></p>
|
|
<p><b><font color="#0066CC" face="Arial">FileDb Classes</font></b></p>
|
|
<p><font face="Arial">The main FileDb classes are: <b>FileDb</b>, <b>Table</b>,
|
|
<b>Field</b> and <b>Record</b>. </font> </p>
|
|
<dir>
|
|
<b>
|
|
<li><font face="Arial">FileDb</font></b><font face="Arial">: Represents a database file. All database operations are
|
|
initiated through this class.<br>
|
|
</li>
|
|
</font>
|
|
<b>
|
|
<li><font face="Arial">Table</font></b><font face="Arial">: Represents a two
|
|
dimensional dataset returned from a query. A Table consists of <b>Fields </b>
|
|
and <b>Records</b>.<br>
|
|
</li>
|
|
</font>
|
|
<b>
|
|
<li><font face="Arial">Field</font></b><font face="Arial">: Defines the
|
|
properties of the table column, such as Name and DataType.<br>
|
|
</li>
|
|
</font>
|
|
<b>
|
|
<li><font face="Arial">Fields</font></b><font face="Arial">: A List of Field
|
|
objects.<br>
|
|
</font></li>
|
|
<li>
|
|
<font face="Arial">
|
|
<b>
|
|
Record</b>: A list of data objects represents a single row in a Table.
|
|
Implements IEnumerable and the Data property which is used for DataBinding.<br>
|
|
</li>
|
|
</font>
|
|
<b>
|
|
<li><font face="Arial">Records</font></b><font face="Arial">: A List of
|
|
Record objects.<br>
|
|
</li>
|
|
</font>
|
|
<b>
|
|
<li><font face="Arial">FieldValues</font></b><font face="Arial">: A simple
|
|
Name/Value pair Dictionary. Use this class when adding and updating records.<br>
|
|
</li>
|
|
</font>
|
|
<b>
|
|
<li><font face="Arial">FilterExpression</font></b><font face="Arial">: Used
|
|
to filter records for query, update and delete.<br>
|
|
</li>
|
|
</font>
|
|
<b>
|
|
<li><font face="Arial">FilterExpressionGroup</font></b><font face="Arial">:
|
|
Used to create compound expressions by grouping FilterExpressions and
|
|
FilterExpressionGroups.<br>
|
|
</font></li>
|
|
</dir>
|
|
<p><b><font color="#0066CC" face="Arial">Database Fields</font></b></p>
|
|
<p><font face="Arial">Fields (or Columns) can be of several common types:
|
|
String, Int, UInt, Bool, Byte, Float, Double and DateTime, or can also be an array of any of
|
|
these types.</font></p>
|
|
<p><font face="Arial">Int Fields can be AutoIncrementing, and you can optionally
|
|
specify one field to be Primary Key (it must be of type Int or String).</font></p>
|
|
<p><font face="Arial">FileDb doesn't support the notion of NULL fields for the
|
|
non-array type. Only array type fields can have NULL values. The non-array field
|
|
values will always have a value, either zero or empty.</font></p>
|
|
<p><font color="#0066CC" face="Arial"><b>FileDb Records</b></font></p>
|
|
<p><font face="Arial">FileDb supports two methods of data retrieval. You can say the
|
|
"default" way is with the built-in Record and Records classes. Think of
|
|
Record as the .NET DataRow class, and think of Table as a DataTable. Table
|
|
is a list of Records, and a Record holds the actual values. You access Field
|
|
values using indexing just as you would a DataRow, like this:</font></p>
|
|
<blockquote>
|
|
<font FACE="Courier New">
|
|
<table border="0" width="100%" id="table25" bgcolor="#FBEDBB" cellpadding="10">
|
|
<tr>
|
|
<td>
|
|
<font face="Courier New" size="2">FileDb employeesDb = new FileDb();<br>
|
|
employeesDb.Open( Employees.fdb" );<br>
|
|
<br>
|
|
Table employees = employeesDb.SelectAllRecords();<br>
|
|
Record record =
|
|
employees[0];<br>
|
|
int id = (int) record["EmployeeId"];<br>
|
|
// or<br>
|
|
id
|
|
= (int) record[0];</font></td>
|
|
</tr>
|
|
</table>
|
|
</font>
|
|
</blockquote>
|
|
<p><font face="Arial">To use a Table with LINQ, you do this:</font></p>
|
|
<blockquote>
|
|
<font FACE="Courier New">
|
|
<table border="0" width="100%" id="table26" bgcolor="#FBEDBB" cellpadding="10">
|
|
<tr>
|
|
<td>
|
|
<font FACE="Courier New" size="2">var recs = from e in
|
|
employees<br>
|
|
where (string)
|
|
e["FirstName"] == "John"<br>
|
|
select e;</font></td>
|
|
</tr>
|
|
</table>
|
|
</font>
|
|
</blockquote>
|
|
<p><font face="Arial">Notice we have to cast the record value to a string.
|
|
This is because, just like with the DataRow, Record
|
|
values are all type object.</font></p>
|
|
<p><font color="#0066CC" face="Arial"><b>Records and Custom Objects</b></font></p>
|
|
<p><font face="Arial">Records are great because they require no additional
|
|
programming and they work with LINQ, albeit with some
|
|
casting. But you can use your own custom classes
|
|
if you want because FileDb has template (generic)
|
|
overloads for each of the SelectRecords methods.
|
|
You only need to create a class with public properties
|
|
which match the names of the fields you want to use.
|
|
Here's an example using the Employees table.</font></p>
|
|
<blockquote>
|
|
<font FACE="Courier New">
|
|
<table border="0" width="100%" id="table27" bgcolor="#FBEDBB" cellpadding="10">
|
|
<tr>
|
|
<td>
|
|
<font FACE="Courier New" size="2">public class Employee<br>
|
|
{<br>
|
|
public int EmployeeID { get; set; }<br>
|
|
public string LastName { get; set; }<br>
|
|
|
|
public string
|
|
FirstName { get; set; }<br>
|
|
|
|
public string Title {
|
|
get; set; }<br>
|
|
|
|
public string
|
|
TitleOfCourtesy { get; set; }<br>
|
|
|
|
public DateTime
|
|
BirthDate { get; set; }<br>
|
|
|
|
public DateTime
|
|
HireDate { get; set; }<br>
|
|
|
|
public string Address
|
|
{ get; set; }<br>
|
|
|
|
public string City {
|
|
get; set; }<br>
|
|
|
|
public string Region {
|
|
get; set; }<br>
|
|
|
|
public string
|
|
PostalCode { get; set; }<br>
|
|
|
|
public string Country
|
|
{ get; set; }<br>
|
|
|
|
public string
|
|
HomePhone { get; set; }<br>
|
|
|
|
public string
|
|
Extension { get; set; }<br>
|
|
|
|
public Byte[] Photo {
|
|
get; set; }<br>
|
|
|
|
public string Notes {
|
|
get; set; }<br>
|
|
|
|
public int ReportsTo {
|
|
get; set; }<br>
|
|
}</font></td>
|
|
</tr>
|
|
</table>
|
|
</font>
|
|
</blockquote>
|
|
<p><font face="Arial">The templated SelectRecords versions return a IList<T>
|
|
where T is your custom type.</font></p>
|
|
<blockquote>
|
|
<font FACE="Courier New">
|
|
<table border="0" width="100%" id="table28" bgcolor="#FBEDBB" cellpadding="10">
|
|
<tr>
|
|
<td>
|
|
<font FACE="Courier New" size="2">
|
|
IList<Employee>
|
|
employees = employeesDb.SelectAllRecords<Employee>();<br>
|
|
Employee employee
|
|
= employees[0];<br>
|
|
int id = Employee.EmployeeId;<br>
|
|
<br>
|
|
var emps = from e in
|
|
employees<br>
|
|
where e.FirstName
|
|
== "John"<br>
|
|
select e;</td>
|
|
</tr>
|
|
</table>
|
|
</font>
|
|
</blockquote>
|
|
<p><font face="Arial">As you can see, this is much cleaner code. And
|
|
its actually more efficient since the Record class has
|
|
more overhead because its not as simple.</font></p>
|
|
<p><b><font color="#0066CC" face="Arial">Searching and Filtering</font></b></p>
|
|
<p><font face="Arial">FileDb uses FilterExpressions and
|
|
FilterExpressionGroups to filter records in queries and
|
|
updates. We use FilterExpressions for simple queries
|
|
which consist of a single field comparison (field =
|
|
'value') and we use FilterExpressionGroups for compound
|
|
expressions, where multiple expressions and grouping are
|
|
required. You can add either FilterExpressions or
|
|
FilterExpressionGroups to a FilterExpressionGroup, thus
|
|
creating complex expresssions (FileDb processes
|
|
FilterExpressionGroups recursively).</font></p>
|
|
<p><font face="Arial">You can either create your own manually in code or
|
|
use the built-in Expression Parser to create them for
|
|
you. The Expression Parser recognizes standard SQL
|
|
comparison operators. You can see it used in the
|
|
examples below. It also recognizes REGEX, which
|
|
uses Regular Expressions, and CONTAINS which uses <b>
|
|
String.Contains</b>. See the section on
|
|
Regular Expressions below for more info. Field names
|
|
prefixed with ~ specifies no-case comparison (for
|
|
strings only).</font></p>
|
|
<p><font face="Arial">Each time you use () around an expression, a new
|
|
FilterExpressionGroup will be created. The inner-most expressions are evaluated
|
|
first, just as in SQL.</font></p>
|
|
<b>
|
|
<p><font color="#333333" face="Arial">Example 1: Create a FilterExpression</font></p>
|
|
</b>
|
|
<blockquote>
|
|
<font FACE="Courier New">
|
|
<table border="0" width="100%" id="table29" bgcolor="#FBEDBB" cellpadding="10">
|
|
<tr>
|
|
<td>
|
|
<font size="2" FACE="Courier New">// build an expression manually<br>
|
|
FilterExpression searchExp = new FilterExpression( "LastName", "Peacock",
|
|
Equality.Equal );<br>
|
|
<br>
|
|
// build the same expression using the
|
|
parser<br>
|
|
searchExp = FilterExpression.Parse( "LastName = 'Peacock'" ); <br>
|
|
Table table = employeesDb.SelectRecords(
|
|
searchExp,
|
|
new string[] { "ID", "LastName" } );<br>
|
|
<br>
|
|
// Or you can simply pass the string filter
|
|
directly - a FilterExpression will be
|
|
created in the same way as above<br>
|
|
<br>
|
|
table = employeesDb.SelectRecords( "LastName
|
|
= 'Peacock'", new string[] { "ID", "LastName"
|
|
} );<br>
|
|
<br>
|
|
foreach( Record record in table )<br>
|
|
{<br>
|
|
foreach( object value in record )<br>
|
|
{<br>
|
|
|
|
Debug.WriteLine( value );<br>
|
|
|
|
}<br>
|
|
}</font></td>
|
|
</tr>
|
|
</table>
|
|
</font>
|
|
</blockquote>
|
|
<b>
|
|
<p><font color="#333333" face="Arial"><br>
|
|
Example 2: Create a FilterExpressionGroup</font></p>
|
|
</b>
|
|
<p><font face="Arial">This example creates two identical FilterExpressionGroups,
|
|
one using the Expression Parser and the other with code.</font></p>
|
|
<blockquote>
|
|
<font FACE="Courier New">
|
|
<table border="0" width="100%" id="table30" bgcolor="#FBEDBB" cellpadding="10">
|
|
<tr>
|
|
<td><font size="2" FACE="Courier New">// For string fields there are
|
|
2 ways to specify </font><font size="2" FACE="Courier New">no-case
|
|
comparisons: you can prefix fieldnames with ~ or you can use ~= as
|
|
demonstrated below<br>
|
|
// The first form is needed when using the IN operator, eg.<br>
|
|
FilterExpressionGroup filterExpGrp =
|
|
FilterExpressionGroup.Parse( "(FirstName ~= 'andrew' OR ~FirstName = 'nancy')
|
|
AND LastName = 'Fuller'" );<br>
|
|
Table table = employeesDb.SelectRecords( filterExpGrp );<br>
|
|
<br>
|
|
// equivalent building it manually<br>
|
|
var fname1Exp = new FilterExpression( "FirstName", "andrew", Equality.Equal,
|
|
MatchType.IgnoreCase );<br>
|
|
var fname2Exp = new FilterExpression( "FirstName", "nancy", Equality.Equal,
|
|
MatchType.IgnoreCase );<br>
|
|
var lnameExp = new FilterExpression( "LastName", "Fuller", Equality.Equal );
|
|
// this constructor defaults to MatchType.UseCase<br>
|
|
var fnamesGrp = new FilterExpressionGroup();<br>
|
|
fnamesGrp.Add( BoolOp.Or, fname1Exp );<br>
|
|
fnamesGrp.Add( BoolOp.Or, fname2Exp );<br>
|
|
var allNamesGrp = new FilterExpressionGroup();<br>
|
|
allNamesGrp.Add( BoolOp.And, lnameExp );<br>
|
|
allNamesGrp.Add( BoolOp.And, fnamesGrp );<br>
|
|
<br>
|
|
table = employeesDb.SelectRecords( allNamesGrp );<br>
|
|
<br>
|
|
// or just pass the filter string directly<br>
|
|
<br>
|
|
table = employeesDb.SelectRecords( "(FirstName ~= 'andrew' OR ~FirstName = 'nancy')
|
|
AND LastName = 'Fuller'" );<br>
|
|
</font></td>
|
|
</tr>
|
|
</table>
|
|
</font>
|
|
</blockquote>
|
|
<p><font face="Arial"><br>
|
|
FileDb supports these comparison operators:</font></p>
|
|
<font face="Arial" size="2">
|
|
<font face="Courier New">
|
|
<blockquote>
|
|
<table border="0" id="table31" style="border-collapse: collapse" bgcolor="#FBEDBB" cellpadding="7">
|
|
<tr>
|
|
<font face="Courier New" size="2">
|
|
<td><b>=</b></td>
|
|
</font><font face="Arial" size="2">
|
|
<td width="18"> </td>
|
|
<font face="Courier New">
|
|
<td><font face="Arial">Equality</font></td>
|
|
</font></font>
|
|
</tr>
|
|
<tr>
|
|
<td>~<b>=</b></td>
|
|
</font><font face="Arial">
|
|
<td width="18"> </td>
|
|
<font face="Courier New">
|
|
<td>No-case equality - strings only</td>
|
|
</tr>
|
|
<tr>
|
|
<td><font face="Courier New"><b><></b></font></td>
|
|
</font><font face="Arial">
|
|
<td width="18"> </td>
|
|
<font face="Courier New">
|
|
<td><font face="Arial">Not Equal</font></td>
|
|
</tr>
|
|
<tr>
|
|
<td><font face="Courier New"><b>!=</b></font></td>
|
|
</font><font face="Arial">
|
|
<td width="18"> </td>
|
|
<font face="Courier New">
|
|
<td><font face="Arial">Not Equal (same as <>)</font></td>
|
|
</tr>
|
|
<tr>
|
|
<td><font face="Courier New"><b>>=</b></font></td>
|
|
</font><font face="Arial">
|
|
<td width="18"> </td>
|
|
<font face="Courier New">
|
|
<td><font face="Arial">Greater than or Equal</font></td>
|
|
</tr>
|
|
<tr>
|
|
<td><font face="Courier New"><b><=</b></font></td>
|
|
</font><font face="Arial">
|
|
<td width="18"> </td>
|
|
<font face="Courier New">
|
|
<td><font face="Arial">Less than or Equal</font></td>
|
|
</tr>
|
|
</font>
|
|
<font face="Courier New" size="2">
|
|
<tr>
|
|
<td><b><font face="Courier New">REGEX</font></b></td>
|
|
</font>
|
|
</font>
|
|
<font face="Arial" size="2">
|
|
<font face="Arial">
|
|
<td width="18"> </td>
|
|
<td><font face="Arial">Use Regular Expression</font></td>
|
|
</tr>
|
|
<tr>
|
|
<font face="Arial" size="2">
|
|
<td><b><font face="Courier New">CONTAINS</font></b></td>
|
|
<font face="Arial">
|
|
<td width="18"> </td>
|
|
<td><font face="Arial">Use the .NET String's Contains method</font></td>
|
|
</font>
|
|
</font>
|
|
</tr>
|
|
<tr>
|
|
<td><b><font face="Courier New">IN</font></b></td>
|
|
<td width="18"> </td>
|
|
<td><font face="Arial">Creates a HashSet of values to use like SQL
|
|
IN operator</font></td>
|
|
</tr>
|
|
<tr>
|
|
<font face="Arial" size="2">
|
|
<td><b><font face="Courier New">NOT</font></b></td>
|
|
<font face="Arial">
|
|
<td width="18"> </td>
|
|
<td><font face="Arial">Logical Negation, e.g NOT CONTAINS</font></td>
|
|
</font>
|
|
</font>
|
|
</tr>
|
|
</table>
|
|
</blockquote>
|
|
</font>
|
|
</font>
|
|
</font></font></font></font></font>
|
|
<font face="Arial" size="2">
|
|
<p> </p>
|
|
</font>
|
|
<p><b><font face="Arial" color="#0066CC">REGEX - </font>
|
|
<font color="#0066CC" face="Arial" size="3">Regular Expressions in searches and filtering</font></b></p>
|
|
<p><font face="Arial" size="3">FileDb supports using Regular Expressions. You can use any RegEx supported by
|
|
.NET. The Expression Parser supports MatchType.RegEx using the REGEX operator.
|
|
Internally, FileDb uses FilterExpressions to evaluate fields. You don't
|
|
need to use them because you can pass in filter strings and they'll be parsed
|
|
into FilterExpressions/FilterExpressionGroups for you. This is just to
|
|
show you how can create them manually if you want to. In
|
|
the example below, both FilterExpressionGroups are identical.</font></p>
|
|
<font FACE="Courier New" size="2">
|
|
<blockquote>
|
|
<font FACE="Courier New">
|
|
<table border="0" id="table32" bgcolor="#FBEDBB" cellpadding="10">
|
|
<tr>
|
|
<td><font size="2" FACE="Courier New">// Using the Expression Parser<br>
|
|
<br>
|
|
// You can use brackets around fieldnames if there are spaces in the
|
|
name<br>
|
|
FilterExpressionGroup filterExpGrp = FilterExpressionGroup.Parse( "(~FirstName = 'steven' OR [FirstName]
|
|
REGEX 'NANCY') AND LastName = 'Fuller'" );<br>
|
|
Table table = employeesDb.SelectRecords( filterExpGrp );<br>
|
|
<br>
|
|
// we can manually build the same FilterExpressionGroup<br>
|
|
var fname1Exp = FilterExpression.Parse( "~FirstName = steven" );<br>
|
|
var fname2Exp = new FilterExpression( "FirstName", "NANCY", Equality.Regex );<br>
|
|
var lnameExp = new FilterExpression( "LastName", "Fuller", Equality.Equal );<br>
|
|
var fnamesGrp = new FilterExpressionGroup();<br>
|
|
fnamesGrp.Add( BoolOp.Or, fname1Exp );<br>
|
|
fnamesGrp.Add( BoolOp.Or, fname2Exp );<br>
|
|
var allNamesGrp = new FilterExpressionGroup();<br>
|
|
allNamesGrp.Add( BoolOp.And, lnameExp );<br>
|
|
allNamesGrp.Add( BoolOp.And, fnamesGrp );<br>
|
|
<br>
|
|
table = employeesDb.SelectRecords( allNamesGrp );</font></td>
|
|
</tr>
|
|
</table>
|
|
</font>
|
|
</blockquote>
|
|
</font>
|
|
<font face="Arial" size="2">
|
|
<p> </p>
|
|
</font>
|
|
<p><b><font color="#0066CC" face="Arial" size="3">Using CONTAINS in searches and filtering</font></b></p>
|
|
<p><font face="Arial" size="3">FileDb supports using Regular Expressions. You can use any RegEx supported by
|
|
.NET. The Expression Parser supports MatchType.RegEx using the REGEX operator.
|
|
Internally, FileDb uses FilterExpressions to evaluate fields. You don't
|
|
need to use them because you can pass in filter strings and they'll be parsed
|
|
into FilterExpressions/FilterExpressionGroups for you. This is just to
|
|
show you how can create them manually if you want to. In
|
|
the example below, both FilterExpressionGroups are identical.</font></p>
|
|
<font FACE="Courier New" size="2">
|
|
<blockquote>
|
|
<font FACE="Courier New">
|
|
<table border="0" id="table42" bgcolor="#FBEDBB" cellpadding="10">
|
|
<tr>
|
|
<td><font size="2" FACE="Courier New">// You can use brackets around fieldnames if there are spaces in the
|
|
name<br>
|
|
FilterExpressionGroup filterExpGrp = FilterExpressionGroup.Parse( "(~FirstName = 'steven' OR [FirstName]
|
|
CONTAINS 'NANC') AND LastName = 'Fuller'" );<br>
|
|
Table table = employeesDb.SelectRecords( filterExpGrp );<br>
|
|
<br>
|
|
// we can manually build the same FilterExpressionGroup<br>
|
|
var fname1Exp = FilterExpression.Parse( "~FirstName = steven" );<br>
|
|
var fname2Exp = new FilterExpression( "FirstName", "NANCY", Equality.Contains );<br>
|
|
var lnameExp = new FilterExpression( "LastName", "Fuller", Equality.Equal );<br>
|
|
var fnamesGrp = new FilterExpressionGroup();<br>
|
|
fnamesGrp.Add( BoolOp.Or, fname1Exp );<br>
|
|
fnamesGrp.Add( BoolOp.Or, fname2Exp );<br>
|
|
var allNamesGrp = new FilterExpressionGroup();<br>
|
|
allNamesGrp.Add( BoolOp.And, lnameExp );<br>
|
|
allNamesGrp.Add( BoolOp.And, fnamesGrp );<br>
|
|
<br>
|
|
table = employeesDb.SelectRecords( allNamesGrp );</font></td>
|
|
</tr>
|
|
</table>
|
|
</font>
|
|
</blockquote>
|
|
</font>
|
|
<p> </p>
|
|
<p><b><font color="#0066CC" face="Arial" size="3">Sort Ordering</font></b></p>
|
|
<p><font face="Arial" size="3">Query methods allow for sorting the results by fields. To
|
|
get a reverse sort, prefix the sort field list with !. To get a no-case sort,
|
|
prefix with ~. To get both reverse and no-case sort, use both ! and ~.</font></p>
|
|
<p><font face="Arial" size="3">Example:</font></p>
|
|
<blockquote>
|
|
<font FACE="Courier New" size="2">
|
|
<table border="0" id="table33" bgcolor="#FBEDBB" cellpadding="10">
|
|
<tr>
|
|
<td>
|
|
<font FACE="Courier New" size="2">
|
|
Table table = employeesDb.SelectAllRecords( new string[] { "ID", "Firstname", "LastName",
|
|
"Age" }, false, new string[] { "~LastName", "~FirstName", "!Age" } );</font></td>
|
|
</tr>
|
|
</table>
|
|
</font>
|
|
</blockquote>
|
|
<p><font color="#0066CC" face="Arial" size="3"><b>Selecting a Table from a Table</b></font></p>
|
|
<p><font face="Arial" size="3">Another very powerful feature of FileDb is the ability to select a Table from
|
|
another Table. This would allow you to be able to select data from a Table
|
|
after the database file has been closed, for example.</font></p>
|
|
<p><font face="Arial" size="3">Example:</font></p>
|
|
<blockquote>
|
|
<font FACE="Courier New" size="2">
|
|
<table border="0" id="table34" bgcolor="#FBEDBB" cellpadding="10">
|
|
<tr>
|
|
<td>
|
|
<font FACE="Courier New" size="2">
|
|
customersDb.Open( path + "Customers.fdb" );<br>
|
|
<br>
|
|
// select all fields and records from the database table<br>
|
|
Table customers = customersDb.SelectAllRecords();<br>
|
|
<br>
|
|
Table subCusts = customers.SelectRecords( "CustomerID <> 'ALFKI'",<br>
|
|
new string[] { "CustomerID", "CompanyName", "City" }, new string[] { "~City", "~CompanyName"
|
|
} );</font></td>
|
|
</tr>
|
|
</table>
|
|
</font>
|
|
</blockquote>
|
|
<p><b><font color="#0066CC" face="Arial" size="3">Encryption</font></b></p>
|
|
<p><font face="Arial" size="3">Using encryption with FileDb is simple. You only need to
|
|
specify a string key when you open the database. After that everything is
|
|
automatic. The only caveat is you must set a key before you add any records.
|
|
Once a single record has been added without a key set you cannot later add
|
|
records with a key. Its all or nothing. Likewise, you cannot add records with
|
|
encryption and later add records without. You must set the encryption key
|
|
each time you add any records.</font></p>
|
|
<p><b><font color="#0066CC" face="Arial" size="3">Persisting Tables</font></b></p>
|
|
<p><font face="Arial" size="3">You can easily save a Table as a new database using
|
|
Table.SaveToDb. This method creates a new database file using the Fields
|
|
in the Table then populates it using the Records in the Table. For
|
|
example, you can select subsets of your data, save it as a new database and send
|
|
it over the Internet.</font></p>
|
|
<blockquote>
|
|
<font FACE="Courier New">
|
|
<table border="0" id="table35" bgcolor="#FBEDBB" cellpadding="10">
|
|
<tr>
|
|
<td><font FACE="Courier New" size="2">Table table = employeesDb.SelectAllRecords( new string[] { "ID", "Firstname", "LastName"
|
|
} );<br>
|
|
table.SaveToDb( "Names.fdb" );</font></td>
|
|
</tr>
|
|
</table>
|
|
</font>
|
|
</blockquote>
|
|
<p><font face="Arial" size="3">You can also save a Table to a database from the
|
|
FileDb Explorer. Just right-click on the Grid to show
|
|
the context menu and select the "Create database from
|
|
Table..." menu item.<br>
|
|
</font></p>
|
|
<p><font color="#0066CC" face="Arial" size="3"><b>Using LINQ to Objects with FileDb</b></font></p>
|
|
<p><font face="Arial" size="3">Microsoft has done an amazing job with LINQ.
|
|
They have invested a huge amount of time, effort and $
|
|
in this technology which allows you to query just about
|
|
any kind of data in a SQL-like way. We use LINQ
|
|
with FileDb to join Tables as we would using SQL.
|
|
The difference is that instead of doing it all in a
|
|
single step with SQL, we must do it in two steps.
|
|
First we select the data Tables from the database files
|
|
then we use LINQ to join them together.</font></p>
|
|
<p><font face="Arial" size="3">LINQ to Objects produces a list of anonymous types as
|
|
its result set. This is good because we get
|
|
strongly typed data objects which we can easily use in WPF/Silverlight apps.</font></p>
|
|
<p><font face="Arial" size="3">Here is an example of doing a simple select using
|
|
LINQ:</font></p>
|
|
<blockquote>
|
|
<font FACE="Courier New">
|
|
<table border="0" id="table36" bgcolor="#FBEDBB" cellpadding="10">
|
|
<tr>
|
|
<td><font face="Courier New" size="2">//
|
|
Using the IN operator. Notice the ~
|
|
prefix on the LastName field. This is how
|
|
<br>
|
|
// you can specify case insensitive searches<br>
|
|
<br>
|
|
Table
|
|
employees = employeesDb.SelectRecords( "~LastName
|
|
IN ('Fuller', 'Peacock')" );<br>
|
|
<br>
|
|
var query =
|
|
from record in employees<br>
|
|
select new<br>
|
|
{<br>
|
|
ID = record["EmployeeId"],<br>
|
|
Name = record["FirstName"] + " " + record["LastName"],<br>
|
|
Title = record["Title"]<br>
|
|
};<br>
|
|
<br>
|
|
foreach( var rec in query )<br>
|
|
{<br>
|
|
Debug.WriteLine( rec.ToString() );<br>
|
|
}</font></td>
|
|
</tr>
|
|
</table>
|
|
</font>
|
|
<p><font face="Arial" size="3">The only thing LINQ did for us in this example was
|
|
gave us a typed list of anonymous objects. Here's
|
|
the same thing but with custom objects:</font></p>
|
|
<font FACE="Courier New">
|
|
<table border="0" id="table37" bgcolor="#FBEDBB" cellpadding="10">
|
|
<tr>
|
|
<td><font size="2">IList<Employee></font><font face="Courier New" size="2"> employees
|
|
= employeesDb.SelectRecords<Employee>(
|
|
"~LastName
|
|
IN ('Fuller', 'Peacock')" );<br>
|
|
<br>
|
|
var query =<br>
|
|
from e in employees<br>
|
|
select e;<br>
|
|
<br>
|
|
foreach( var emp in query )<br>
|
|
{<br>
|
|
Debug.WriteLine( emp.ToString() );<br>
|
|
}</font></td>
|
|
</tr>
|
|
</table>
|
|
</font>
|
|
</blockquote>
|
|
<p dir="ltr"><font face="Arial" size="3">Now lets tap into LINQ's real power to join tables together
|
|
like a SQL inner join. Notice in the following example we use the </font>
|
|
<font face="Courier New" size="2">FilterExpression.CreateInExpressionFromTable</font><font face="Arial"><font size="3">
|
|
method. We do this to get only the records we are going to need with LINQ.
|
|
So using FileDb with LINQ is a two step process. You first select the
|
|
records you will need then use them in the LINQ query. If your database
|
|
files are large, you can filter the records like this. Otherwise you can
|
|
just select all records.</font></p>
|
|
<blockquote>
|
|
<font FACE="Courier New">
|
|
<table border="0" id="table38" bgcolor="#FBEDBB" cellpadding="10">
|
|
<tr>
|
|
<td><font face="Courier New" size="2">FileDb customersDb = new FileDb(),<br>
|
|
ordersDb = new FileDb(),<br>
|
|
orderDetailsDb = new FileDb(),<br>
|
|
productsDb = new FileDb();<br>
|
|
<br>
|
|
customersDb.Open( "Customers.fdb" );<br>
|
|
ordersDb.Open( "Orders.fdb" );<br>
|
|
orderDetailsDb.Open( "OrderDetails.fdb" );<br>
|
|
productsDb.Open( "Products.fdb" );<br>
|
|
<br>
|
|
// get our target Customer records<br>
|
|
// Note that we should select only fields we
|
|
need from each table, but to keep the code<br>
|
|
// simple for this example we just pass in null for the field
|
|
list<br>
|
|
<br>
|
|
FilterExpression filterExp =
|
|
FilterExpression.Parse( "CustomerID IN( 'ALFKI',
|
|
'BONAP' )" );<br>
|
|
FileDbNs.Table customers =
|
|
customersDb.SelectRecords( filterExp );<br>
|
|
<br>
|
|
// now get only Order records for the target
|
|
Customer records<br>
|
|
// CreateInExpressionFromTable will create
|
|
an IN FilterExpression, which uses a HashSet
|
|
<br>
|
|
// for high efficiency when filtering
|
|
records<br>
|
|
<br>
|
|
filterExp =
|
|
FilterExpression.CreateInExpressionFromTable(
|
|
"CustomerID", customers, "CustomerID" );<br>
|
|
FileDbNs.Table orders =
|
|
ordersDb.SelectRecords( filterExp );<br>
|
|
<br>
|
|
// now get only OrderDetails records for the
|
|
target Order records<br>
|
|
<br>
|
|
filterExp =
|
|
FilterExpression.CreateInExpressionFromTable(
|
|
"OrderID", orders, "OrderID" );<br>
|
|
FileDbNs.Table orderDetails =
|
|
orderDetailsDb.SelectRecords( filterExp );<br>
|
|
<br>
|
|
// now get only Product records for the
|
|
target OrderDetails records<br>
|
|
<br>
|
|
filterExp =
|
|
FilterExpression.CreateInExpressionFromTable(
|
|
"ProductID", orderDetails, "ProductID" );<br>
|
|
FileDbNs.Table products =
|
|
productsDb.SelectRecords( filterExp );<br>
|
|
<br>
|
|
// now we're ready to do the join<br>
|
|
<br>
|
|
var query =<br>
|
|
from custRec in customers<br>
|
|
join orderRec in orders on custRec["CustomerID"]
|
|
equals orderRec["CustomerID"]<br>
|
|
join orderDetailRec in orderDetails on
|
|
orderRec["OrderID"] equals
|
|
orderDetailRec["OrderID"]<br>
|
|
join productRec in products on
|
|
orderDetailRec["ProductID"] equals
|
|
productRec["ProductID"]<br>
|
|
select new<br>
|
|
{<br>
|
|
ID = custRec["CustomerID"],<br>
|
|
CompanyName = custRec["CompanyName"],<br>
|
|
OrderID = orderRec["OrderID"],<br>
|
|
OrderDate = orderRec["OrderDate"],<br>
|
|
ProductName = productRec["ProductName"],<br>
|
|
UnitPrice = orderDetailRec["UnitPrice"],<br>
|
|
Quantity = orderDetailRec["Quantity"]<br>
|
|
};<br>
|
|
<br>
|
|
foreach( var rec in query )<br>
|
|
{<br>
|
|
Debug.WriteLine( rec.ToString() );<br>
|
|
}</font></td>
|
|
</tr>
|
|
</table>
|
|
</font>
|
|
<p><font face="Arial" size="3">Here's the same thing again using custom objects:</font></p>
|
|
<font FACE="Courier New">
|
|
<table border="0" id="table39" bgcolor="#FBEDBB" cellpadding="10">
|
|
<tr>
|
|
<td><font face="Courier New" size="2">// get our target Customer records<br>
|
|
<br>
|
|
FilterExpression filterExp =
|
|
FilterExpression.Parse( "CustomerID IN( 'ALFKI',
|
|
'BONAP' )" );<br>
|
|
IList<Customer> customers =
|
|
customersDb.SelectRecords<Customer>( filterExp );<br>
|
|
<br>
|
|
filterExp =
|
|
FilterExpression.CreateInExpressionFromTable<Customer>(
|
|
"CustomerID", customers, "CustomerID" );<br>
|
|
IList<Order> orders =
|
|
ordersDb.SelectRecords<Order>( filterExp );<br>
|
|
<br>
|
|
// now get only OrderDetails records for the
|
|
target Order records<br>
|
|
<br>
|
|
filterExp =
|
|
FilterExpression.CreateInExpressionFromTable<Order>(
|
|
"OrderID", orders, "OrderID" );<br>
|
|
IList<OrderDetail> orderDetails =
|
|
orderDetailsDb.SelectRecords<OrderDetail>( filterExp );<br>
|
|
<br>
|
|
// now get only Product records for the
|
|
target OrderDetails records<br>
|
|
<br>
|
|
filterExp =
|
|
FilterExpression.CreateInExpressionFromTable<OrderDetail>(
|
|
"ProductID", orderDetails, "ProductID" );<br>
|
|
IList<Product> products =
|
|
productsDb.SelectRecords<Product>(( filterExp );<br>
|
|
<br>
|
|
// now we're ready to do the join<br>
|
|
<br>
|
|
var query =<br>
|
|
from custRec in customers<br>
|
|
join orderRec in orders on custRec.CustomerID
|
|
equals orderRec.CustomerID<br>
|
|
join orderDetailRec in orderDetails on
|
|
orderRec.OrderID equals orderDetailRec.OrderID<br>
|
|
join productRec in products on
|
|
orderDetailRec.ProductID equals productRec.ProductID<br>
|
|
select new<br>
|
|
{<br>
|
|
ID = custRec.CustomerID,<br>
|
|
CompanyName = custRec.CompanyName,<br>
|
|
OrderID = orderRec.OrderID,<br>
|
|
OrderDate = orderRec.OrderDate,<br>
|
|
ProductName = productRec.ProductName,<br>
|
|
UnitPrice = orderDetailRec.UnitPrice,<br>
|
|
Quantity = orderDetailRec.Quantity<br>
|
|
};<br>
|
|
<br>
|
|
foreach( var rec in query )<br>
|
|
{<br>
|
|
Debug.WriteLine( rec.ToString() );<br>
|
|
}</font></td>
|
|
</tr>
|
|
</table>
|
|
</blockquote>
|
|
<p> </p>
|
|
</font>
|
|
<p><b>
|
|
<font color="#0066CC" face="Arial" size="3">Creating a Database</font></p>
|
|
</b>
|
|
<p><font face="Arial" size="3">You create your database programmatically by defining
|
|
Fields and adding them to an array then calling FileDb.Create, similar to below.
|
|
Notice we set the ID field to be AutoIncrementing and PrimaryKey. This code
|
|
creates a database with every type of field.</font></p>
|
|
<font FACE="Courier New">
|
|
<blockquote>
|
|
<table border="0" width="100%" id="table40" bgcolor="#FBEDBB" cellpadding="10">
|
|
<tr>
|
|
<td><font size="2" FACE="Courier New">Field field;<br>
|
|
var fieldLst = new List<Field>( 20 );<br>
|
|
field = new Field( "ID", DataType.Int );<br>
|
|
field.AutoIncStart = 0;<br>
|
|
field.IsPrimaryKey = true;<br>
|
|
fields.Add( field );<br>
|
|
field = new Field( "FirstName", DataType.String );<br>
|
|
fields.Add( field );<br>
|
|
field = new Field( "LastName", DataType.String );<br>
|
|
fields.Add( field );<br>
|
|
field = new Field( "BirthDate", DataType.DateTime );<br>
|
|
fields.Add( field );<br>
|
|
field = new Field( "IsCitizen", DataType.Bool );<br>
|
|
fields.Add( field );<br>
|
|
field = new Field( "DoubleField", DataType.Double );<br>
|
|
fields.Add( field );<br>
|
|
field = new Field( "ByteField", DataType.Byte );<br>
|
|
fields.Add( field );<br>
|
|
<br>
|
|
// array types<br>
|
|
field = new Field( "StringArrayField", DataType.String );<br>
|
|
field.IsArray = true;<br>
|
|
fields.Add( field );<br>
|
|
field = new Field( "ByteArrayField", DataType.Byte );<br>
|
|
field.IsArray = true;<br>
|
|
fields.Add( field );<br>
|
|
field = new Field( "IntArrayField", DataType.Int );<br>
|
|
field.IsArray = true;<br>
|
|
fields.Add( field );<br>
|
|
field = new Field( "DoubleArrayField", DataType.Double );<br>
|
|
field.IsArray = true;<br>
|
|
fields.Add( field );<br>
|
|
field = new Field( "DateTimeArrayField", DataType.DateTime );<br>
|
|
field.IsArray = true;<br>
|
|
fields.Add( field );<br>
|
|
field = new Field( "BoolArray", DataType.Bool );<br>
|
|
field.IsArray = true;<br>
|
|
fields.Add( field );</font><font size="2"><br>
|
|
<br>
|
|
var myDb = new FileDb();</font><font size="2" FACE="Courier New"><br>
|
|
myDb.Create( "MyDatabase.fdb", fieldLst.ToArray() );</font></td>
|
|
</tr>
|
|
</table>
|
|
</blockquote>
|
|
</font>
|
|
<p><b><font color="#0066CC" face="Arial" size="3"><br>
|
|
Adding Records</font></b></p>
|
|
<p><font face="Arial" size="3">You add records to a database by creating a FieldValues
|
|
object and adding field values. You do not need to represent every field of the
|
|
database. Fields that are missing will be initialized to the default value (zero
|
|
for numeric types, DateTime.MinValue,
|
|
empty for String and NULL for array types).</font></p>
|
|
<font FACE="Courier New">
|
|
<blockquote>
|
|
<table border="0" width="100%" id="table41" bgcolor="#FBEDBB" cellpadding="10">
|
|
<tr>
|
|
<td>
|
|
<font size="2" FACE="Courier New">var record = new FieldValues();<br>
|
|
record.Add( "FirstName", "Nancy" );<br>
|
|
record.Add( "LastName", "Davolio" );<br>
|
|
record.Add( "BirthDate", new DateTime( 1968, 12, 8 ) );<br>
|
|
record.Add( "IsCitizen", true );<br>
|
|
record.Add( "Double", 1.23 );<br>
|
|
record.Add( "Byte", 1 );<br>
|
|
record.Add( "StringArray", new string[] { "s1", "s2", "s3" } );<br>
|
|
record.Add( "ByteArray", new Byte[] { 1, 2, 3, 4 } );<br>
|
|
record.Add( "IntArray", new int[] { 100, 200, 300, 400 } );<br>
|
|
record.Add( "DoubleArray", new double[] { 1.2, 2.4, 3.6, 4.8 } );<br>
|
|
record.Add( "DateTimeArray", new DateTime[] { DateTime.Now, DateTime.Now,
|
|
DateTime.Now, DateTime.Now } );<br>
|
|
record.Add( "BoolArray", new bool[] { true, false, true, false } );<br>
|
|
<br>
|
|
myDb.AddRecord( record );</font></td>
|
|
</tr>
|
|
</table>
|
|
</blockquote>
|
|
<p> </p>
|
|
</font>
|
|
|
|
</body>
|
|
|
|
</html> |