XAML-Map-Control/Caching/FileDb/Help.html
ClemensF 3b6545e738 Version 2.4.0.
- Added ImageFileCache and FileDbCache for WinRT
- Improved TileImageLoader
- Removed TileContainer, TileLayer can be added as MapBase child
- Removed attached property MapPanel.ViewportPosition
2014-11-19 21:11:14 +01:00

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.&nbsp; <u>FileDb is a No-SQL database</u>
meant for use as a local data store for applications.&nbsp;
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.&nbsp;
So you can just as easily read/write a String[] field as
you would an Int field.&nbsp; Another feature is that a
database file created on any .NET platform will work on
any other.&nbsp; 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 &quot;flat-file&quot; database, using
LINQ it becomes fully relational!&nbsp; 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.&nbsp;
(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 = &quot;FirstName IN (&#39;Cindy&#39;, &#39;John&#39;) AND Age &gt; 32&quot;</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.&nbsp; 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.&nbsp; This is much easier than using Sqlite
wrappers.&nbsp; 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.&nbsp;&nbsp; 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 &quot;all or nothing&quot;, 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.&nbsp;
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>
&nbsp;</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>
&nbsp;</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>
&nbsp;</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>
&nbsp;</li>
</font>
<b>
<li><font face="Arial">Fields</font></b><font face="Arial">: A List of Field
objects.<br>
&nbsp;</font></li>
<li>
<font face="Arial">
<b>
Record</b>: A list of data objects represents a single row in a Table.&nbsp;
Implements IEnumerable and the Data property which is used for DataBinding.<br>
&nbsp;</li>
</font>
<b>
<li><font face="Arial">Records</font></b><font face="Arial">: A List of
Record objects.<br>
&nbsp;</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>
&nbsp;</li>
</font>
<b>
<li><font face="Arial">FilterExpression</font></b><font face="Arial">: Used
to filter records for query, update and delete.<br>
&nbsp;</li>
</font>
<b>
<li><font face="Arial">FilterExpressionGroup</font></b><font face="Arial">:
Used to create compound expressions by grouping FilterExpressions and
FilterExpressionGroups.<br>
&nbsp;</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.&nbsp; You can say the
&quot;default&quot; way is with the built-in Record and Records classes.&nbsp; Think of
Record as the .NET DataRow class, and think of Table as a DataTable.&nbsp; 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&quot; );<br>
<br>
Table employees = employeesDb.SelectAllRecords();<br>
Record record =
employees[0];<br>
int id = (int) record[&quot;EmployeeId&quot;];<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>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; where (string)
e[&quot;FirstName&quot;] == &quot;John&quot;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; select e;</font></td>
</tr>
</table>
</font>
</blockquote>
<p><font face="Arial">Notice we have to cast the record value to a string.&nbsp;
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.&nbsp; But you can use your own custom classes
if you want because FileDb has template (generic)
overloads for each of the SelectRecords methods.&nbsp;
You only need to create a class with public properties
which match the names of the fields you want to use.&nbsp;
Here&#39;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>
&nbsp;&nbsp;&nbsp; public int EmployeeID { get; set; }<br>
&nbsp;&nbsp;&nbsp; public string LastName { get; set; }<br>
&nbsp;&nbsp;&nbsp;
public string
FirstName { get; set; }<br>
&nbsp;&nbsp;&nbsp;
public string Title {
get; set; }<br>
&nbsp;&nbsp;&nbsp;
public string
TitleOfCourtesy { get; set; }<br>
&nbsp;&nbsp;&nbsp;
public DateTime
BirthDate { get; set; }<br>
&nbsp;&nbsp;&nbsp;
public DateTime
HireDate { get; set; }<br>
&nbsp;&nbsp;&nbsp;
public string Address
{ get; set; }<br>
&nbsp;&nbsp;&nbsp;
public string City {
get; set; }<br>
&nbsp;&nbsp;&nbsp;
public string Region {
get; set; }<br>
&nbsp;&nbsp;&nbsp;
public string
PostalCode { get; set; }<br>
&nbsp;&nbsp;&nbsp;
public string Country
{ get; set; }<br>
&nbsp;&nbsp;&nbsp;
public string
HomePhone { get; set; }<br>
&nbsp;&nbsp;&nbsp;
public string
Extension { get; set; }<br>
&nbsp;&nbsp;&nbsp;
public Byte[] Photo {
get; set; }<br>
&nbsp;&nbsp;&nbsp;
public string Notes {
get; set; }<br>
&nbsp;&nbsp;&nbsp;
public int ReportsTo {
get; set; }<br>
}</font></td>
</tr>
</table>
</font>
</blockquote>
<p><font face="Arial">The templated SelectRecords versions return a IList&lt;T&gt;
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&lt;Employee&gt;
employees = employeesDb.SelectAllRecords&lt;Employee&gt;();<br>
Employee employee
= employees[0];<br>
int id = Employee.EmployeeId;<br>
<br>
var emps = from e in
employees<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; where e.FirstName
== &quot;John&quot;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; select e;</td>
</tr>
</table>
</font>
</blockquote>
<p><font face="Arial">As you can see, this is much cleaner code.&nbsp; 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 =
&#39;value&#39;) 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( &quot;LastName&quot;, &quot;Peacock&quot;,
Equality.Equal );<br>
<br>
// build the same expression using the
parser<br>
searchExp = FilterExpression.Parse( &quot;LastName = 'Peacock'&quot; ); <br>
Table table = employeesDb.SelectRecords(
searchExp,
new string[] { &quot;ID&quot;, &quot;LastName&quot; } );<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( &quot;LastName
= &#39;Peacock&#39;&quot;, new string[] { &quot;ID&quot;, &quot;LastName&quot;
} );<br>
<br>
foreach( Record record in table )<br>
{<br>
&nbsp;&nbsp;&nbsp; foreach( object value in record )<br>
&nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
Debug.WriteLine( value );<br>
&nbsp;&nbsp;&nbsp;
}<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( &quot;(FirstName ~= 'andrew' OR ~FirstName = 'nancy')
AND LastName = 'Fuller'&quot; );<br>
Table table = employeesDb.SelectRecords( filterExpGrp );<br>
<br>
// equivalent building it manually<br>
var fname1Exp = new FilterExpression( &quot;FirstName&quot;, &quot;andrew&quot;, Equality.Equal,
MatchType.IgnoreCase );<br>
var fname2Exp = new FilterExpression( &quot;FirstName&quot;, &quot;nancy&quot;, Equality.Equal,
MatchType.IgnoreCase );<br>
var lnameExp = new FilterExpression( &quot;LastName&quot;, &quot;Fuller&quot;, 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( &quot;(FirstName ~= 'andrew' OR ~FirstName = 'nancy')
AND LastName = &#39;Fuller&#39;&quot; );<br>
&nbsp;</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">&nbsp;</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">&nbsp;</td>
<font face="Courier New">
<td>No-case equality - strings only</td>
</tr>
<tr>
<td><font face="Courier New"><b>&lt;&gt;</b></font></td>
</font><font face="Arial">
<td width="18">&nbsp;</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">&nbsp;</td>
<font face="Courier New">
<td><font face="Arial">Not Equal (same as &lt;&gt;)</font></td>
</tr>
<tr>
<td><font face="Courier New"><b>&gt;=</b></font></td>
</font><font face="Arial">
<td width="18">&nbsp;</td>
<font face="Courier New">
<td><font face="Arial">Greater than or Equal</font></td>
</tr>
<tr>
<td><font face="Courier New"><b>&lt;=</b></font></td>
</font><font face="Arial">
<td width="18">&nbsp;</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">&nbsp;</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">&nbsp;</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">&nbsp;</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">&nbsp;</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>&nbsp;</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.&nbsp;
Internally, FileDb uses FilterExpressions to evaluate fields.&nbsp; You don&#39;t
need to use them because you can pass in filter strings and they&#39;ll be parsed
into FilterExpressions/FilterExpressionGroups for you.&nbsp; This is just to
show you how can create them manually if you want to.&nbsp; 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( &quot;(~FirstName = 'steven' OR [FirstName]
REGEX 'NANCY') AND LastName = 'Fuller'&quot; );<br>
Table table = employeesDb.SelectRecords( filterExpGrp );<br>
<br>
// we can manually build the same FilterExpressionGroup<br>
var fname1Exp = FilterExpression.Parse( &quot;~FirstName = steven&quot; );<br>
var fname2Exp = new FilterExpression( &quot;FirstName&quot;, &quot;NANCY&quot;, Equality.Regex );<br>
var lnameExp = new FilterExpression( &quot;LastName&quot;, &quot;Fuller&quot;, 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>&nbsp;</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.&nbsp;
Internally, FileDb uses FilterExpressions to evaluate fields.&nbsp; You don&#39;t
need to use them because you can pass in filter strings and they&#39;ll be parsed
into FilterExpressions/FilterExpressionGroups for you.&nbsp; This is just to
show you how can create them manually if you want to.&nbsp; 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( &quot;(~FirstName = 'steven' OR [FirstName]
CONTAINS 'NANC') AND LastName = 'Fuller'&quot; );<br>
Table table = employeesDb.SelectRecords( filterExpGrp );<br>
<br>
// we can manually build the same FilterExpressionGroup<br>
var fname1Exp = FilterExpression.Parse( &quot;~FirstName = steven&quot; );<br>
var fname2Exp = new FilterExpression( &quot;FirstName&quot;, &quot;NANCY&quot;, Equality.Contains );<br>
var lnameExp = new FilterExpression( &quot;LastName&quot;, &quot;Fuller&quot;, 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>&nbsp;</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[] { &quot;ID&quot;, &quot;Firstname&quot;, &quot;LastName&quot;,
&quot;Age&quot; }, false, new string[] { &quot;~LastName&quot;, &quot;~FirstName&quot;, &quot;!Age&quot; } );</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.&nbsp; 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 + &quot;Customers.fdb&quot; );<br>
<br>
// select all fields and records from the database table<br>
Table customers = customersDb.SelectAllRecords();<br>
<br>
Table subCusts = customers.SelectRecords( &quot;CustomerID &lt;&gt; &#39;ALFKI&#39;&quot;,<br>
new string[] { &quot;CustomerID&quot;, &quot;CompanyName&quot;, &quot;City&quot; }, new string[] { &quot;~City&quot;, &quot;~CompanyName&quot;
} );</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.&nbsp; 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.&nbsp; This method creates a new database file using the Fields
in the Table then populates it using the Records in the Table.&nbsp; 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[] { &quot;ID&quot;, &quot;Firstname&quot;, &quot;LastName&quot;
} );<br>
table.SaveToDb( &quot;Names.fdb&quot; );</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 &quot;Create database from
Table...&quot; menu item.<br>
&nbsp;</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.&nbsp;
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.&nbsp; We use LINQ
with FileDb to join Tables as we would using SQL.&nbsp;
The difference is that instead of doing it all in a
single step with SQL, we must do it in two steps.&nbsp;
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.&nbsp; 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.&nbsp; Notice the ~
prefix on the LastName field. This is how
<br>
// you can specify case insensitive searches<br>
<br>
Table
employees = employeesDb.SelectRecords( &quot;~LastName
IN (&#39;Fuller&#39;, &#39;Peacock&#39;)&quot; );<br>
<br>
var query =
from record in employees<br>
select new<br>
{<br>
&nbsp;&nbsp;&nbsp; ID = record[&quot;EmployeeId&quot;],<br>
&nbsp;&nbsp;&nbsp; Name = record[&quot;FirstName&quot;] + &quot; &quot; + record[&quot;LastName&quot;],<br>
&nbsp;&nbsp;&nbsp; Title = record[&quot;Title&quot;]<br>
};<br>
<br>
foreach( var rec in query )<br>
{<br>
&nbsp;&nbsp;&nbsp; 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.&nbsp; Here&#39;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&lt;Employee&gt;</font><font face="Courier New" size="2"> employees
= employeesDb.SelectRecords&lt;Employee&gt;(
&quot;~LastName
IN (&#39;Fuller&#39;, &#39;Peacock&#39;)&quot; );<br>
<br>
var query =<br>
from e in employees<br>
select e;<br>
<br>
foreach( var emp in query )<br>
{<br>
&nbsp;&nbsp;&nbsp; Debug.WriteLine( emp.ToString() );<br>
}</font></td>
</tr>
</table>
</font>
</blockquote>
<p dir="ltr"><font face="Arial" size="3">Now lets tap into LINQ&#39;s real power to join tables together
like a SQL inner join.&nbsp; 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.&nbsp; We do this to get only the records we are going to need with LINQ.&nbsp;
So using FileDb with LINQ is a two step process.&nbsp; You first select the
records you will need then use them in the LINQ query.&nbsp; If your database
files are large, you can filter the records like this.&nbsp; 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( &quot;Customers.fdb&quot; );<br>
ordersDb.Open( &quot;Orders.fdb&quot; );<br>
orderDetailsDb.Open( &quot;OrderDetails.fdb&quot; );<br>
productsDb.Open( &quot;Products.fdb&quot; );<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( &quot;CustomerID IN( &#39;ALFKI&#39;,
&#39;BONAP&#39; )&quot; );<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>
&nbsp;<br>
filterExp =
FilterExpression.CreateInExpressionFromTable(
&quot;CustomerID&quot;, customers, &quot;CustomerID&quot; );<br>
FileDbNs.Table orders =
ordersDb.SelectRecords( filterExp );<br>
<br>
// now get only OrderDetails records for the
target Order records<br>
<br>
filterExp =
FilterExpression.CreateInExpressionFromTable(
&quot;OrderID&quot;, orders, &quot;OrderID&quot; );<br>
FileDbNs.Table orderDetails =
orderDetailsDb.SelectRecords( filterExp );<br>
<br>
// now get only Product records for the
target OrderDetails records<br>
<br>
filterExp =
FilterExpression.CreateInExpressionFromTable(
&quot;ProductID&quot;, orderDetails, &quot;ProductID&quot; );<br>
FileDbNs.Table products =
productsDb.SelectRecords( filterExp );<br>
<br>
// now we&#39;re ready to do the join<br>
<br>
var query =<br>
&nbsp;&nbsp;&nbsp; from custRec in customers<br>
&nbsp;&nbsp;&nbsp; join orderRec in orders on custRec[&quot;CustomerID&quot;]
equals orderRec[&quot;CustomerID&quot;]<br>
&nbsp;&nbsp;&nbsp; join orderDetailRec in orderDetails on
orderRec[&quot;OrderID&quot;] equals
orderDetailRec[&quot;OrderID&quot;]<br>
&nbsp;&nbsp;&nbsp; join productRec in products on
orderDetailRec[&quot;ProductID&quot;] equals
productRec[&quot;ProductID&quot;]<br>
&nbsp;&nbsp;&nbsp; select new<br>
&nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ID = custRec[&quot;CustomerID&quot;],<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CompanyName = custRec[&quot;CompanyName&quot;],<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OrderID = orderRec[&quot;OrderID&quot;],<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OrderDate = orderRec[&quot;OrderDate&quot;],<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ProductName = productRec[&quot;ProductName&quot;],<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UnitPrice = orderDetailRec[&quot;UnitPrice&quot;],<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Quantity = orderDetailRec[&quot;Quantity&quot;]<br>
&nbsp;&nbsp;&nbsp; };<br>
<br>
foreach( var rec in query )<br>
{<br>
&nbsp;&nbsp;&nbsp; Debug.WriteLine( rec.ToString() );<br>
}</font></td>
</tr>
</table>
</font>
<p><font face="Arial" size="3">Here&#39;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( &quot;CustomerID IN( &#39;ALFKI&#39;,
&#39;BONAP&#39; )&quot; );<br>
IList&lt;Customer&gt; customers =
customersDb.SelectRecords&lt;Customer&gt;( filterExp );<br>
&nbsp;<br>
filterExp =
FilterExpression.CreateInExpressionFromTable&lt;Customer&gt;(
&quot;CustomerID&quot;, customers, &quot;CustomerID&quot; );<br>
IList&lt;Order&gt; orders =
ordersDb.SelectRecords&lt;Order&gt;( filterExp );<br>
<br>
// now get only OrderDetails records for the
target Order records<br>
<br>
filterExp =
FilterExpression.CreateInExpressionFromTable&lt;Order&gt;(
&quot;OrderID&quot;, orders, &quot;OrderID&quot; );<br>
IList&lt;OrderDetail&gt; orderDetails =
orderDetailsDb.SelectRecords&lt;OrderDetail&gt;( filterExp );<br>
<br>
// now get only Product records for the
target OrderDetails records<br>
<br>
filterExp =
FilterExpression.CreateInExpressionFromTable&lt;OrderDetail&gt;(
&quot;ProductID&quot;, orderDetails, &quot;ProductID&quot; );<br>
IList&lt;Product&gt; products =
productsDb.SelectRecords&lt;Product&gt;(( filterExp );<br>
<br>
// now we&#39;re ready to do the join<br>
<br>
var query =<br>
&nbsp;&nbsp;&nbsp; from custRec in customers<br>
&nbsp;&nbsp;&nbsp; join orderRec in orders on custRec.CustomerID
equals orderRec.CustomerID<br>
&nbsp;&nbsp;&nbsp; join orderDetailRec in orderDetails on
orderRec.OrderID equals orderDetailRec.OrderID<br>
&nbsp;&nbsp;&nbsp; join productRec in products on
orderDetailRec.ProductID equals productRec.ProductID<br>
&nbsp;&nbsp;&nbsp; select new<br>
&nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ID = custRec.CustomerID,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CompanyName = custRec.CompanyName,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OrderID = orderRec.OrderID,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; OrderDate = orderRec.OrderDate,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ProductName = productRec.ProductName,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UnitPrice = orderDetailRec.UnitPrice,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Quantity = orderDetailRec.Quantity<br>
&nbsp;&nbsp;&nbsp; };<br>
<br>
foreach( var rec in query )<br>
{<br>
&nbsp;&nbsp;&nbsp; Debug.WriteLine( rec.ToString() );<br>
}</font></td>
</tr>
</table>
</blockquote>
<p>&nbsp;</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&lt;Field&gt;( 20 );<br>
field = new Field( &quot;ID&quot;, DataType.Int );<br>
field.AutoIncStart = 0;<br>
field.IsPrimaryKey = true;<br>
fields.Add( field );<br>
field = new Field( &quot;FirstName&quot;, DataType.String );<br>
fields.Add( field );<br>
field = new Field( &quot;LastName&quot;, DataType.String );<br>
fields.Add( field );<br>
field = new Field( &quot;BirthDate&quot;, DataType.DateTime );<br>
fields.Add( field );<br>
field = new Field( &quot;IsCitizen&quot;, DataType.Bool );<br>
fields.Add( field );<br>
field = new Field( &quot;DoubleField&quot;, DataType.Double );<br>
fields.Add( field );<br>
field = new Field( &quot;ByteField&quot;, DataType.Byte );<br>
fields.Add( field );<br>
<br>
// array types<br>
field = new Field( &quot;StringArrayField&quot;, DataType.String );<br>
field.IsArray = true;<br>
fields.Add( field );<br>
field = new Field( &quot;ByteArrayField&quot;, DataType.Byte );<br>
field.IsArray = true;<br>
fields.Add( field );<br>
field = new Field( &quot;IntArrayField&quot;, DataType.Int );<br>
field.IsArray = true;<br>
fields.Add( field );<br>
field = new Field( &quot;DoubleArrayField&quot;, DataType.Double );<br>
field.IsArray = true;<br>
fields.Add( field );<br>
field = new Field( &quot;DateTimeArrayField&quot;, DataType.DateTime );<br>
field.IsArray = true;<br>
fields.Add( field );<br>
field = new Field( &quot;BoolArray&quot;, 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( &quot;MyDatabase.fdb&quot;, 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( &quot;FirstName&quot;, &quot;Nancy&quot; );<br>
record.Add( &quot;LastName&quot;, &quot;Davolio&quot; );<br>
record.Add( &quot;BirthDate&quot;, new DateTime( 1968, 12, 8 ) );<br>
record.Add( &quot;IsCitizen&quot;, true );<br>
record.Add( &quot;Double&quot;, 1.23 );<br>
record.Add( &quot;Byte&quot;, 1 );<br>
record.Add( &quot;StringArray&quot;, new string[] { &quot;s1&quot;, &quot;s2&quot;, &quot;s3&quot; } );<br>
record.Add( &quot;ByteArray&quot;, new Byte[] { 1, 2, 3, 4 } );<br>
record.Add( &quot;IntArray&quot;, new int[] { 100, 200, 300, 400 } );<br>
record.Add( &quot;DoubleArray&quot;, new double[] { 1.2, 2.4, 3.6, 4.8 } );<br>
record.Add( &quot;DateTimeArray&quot;, new DateTime[] { DateTime.Now, DateTime.Now,
DateTime.Now, DateTime.Now } );<br>
record.Add( &quot;BoolArray&quot;, new bool[] { true, false, true, false } );<br>
<br>
myDb.AddRecord( record );</font></td>
</tr>
</table>
</blockquote>
<p>&nbsp;</p>
</font>
</body>
</html>