From a860c8d341ecc2cb354d4daa2c2ad6b8c5e19364 Mon Sep 17 00:00:00 2001 From: ClemensF Date: Tue, 16 Jul 2019 20:13:52 +0200 Subject: [PATCH] Version 4.12.2 Updated FileDbCache and MapImages --- FileDbCache/FileDb/FileDb.dll | Bin 87040 -> 0 bytes FileDbCache/FileDb/FileDb.xml | 1910 ----------------------- FileDbCache/FileDb/FileDbPcl.dll | Bin 80384 -> 0 bytes FileDbCache/FileDb/FileDbPcl.xml | 1854 ---------------------- FileDbCache/FileDb/Help.html | 983 ------------ FileDbCache/UWP/FileDbCache.UWP.csproj | 9 +- FileDbCache/UWP/FileDbCache.cs | 47 +- FileDbCache/WPF/FileDbCache.WPF.csproj | 5 +- FileDbCache/WPF/packages.config | 4 + MapControl/Shared/TileImageLoader.cs | 68 +- MapImages/Shared/GroundOverlayPanel.cs | 43 - MapImages/UWP/GroundOverlayPanel.UWP.cs | 43 + MapImages/WPF/GroundOverlayPanel.WPF.cs | 47 + 13 files changed, 148 insertions(+), 4865 deletions(-) delete mode 100644 FileDbCache/FileDb/FileDb.dll delete mode 100644 FileDbCache/FileDb/FileDb.xml delete mode 100644 FileDbCache/FileDb/FileDbPcl.dll delete mode 100644 FileDbCache/FileDb/FileDbPcl.xml delete mode 100644 FileDbCache/FileDb/Help.html create mode 100644 FileDbCache/WPF/packages.config diff --git a/FileDbCache/FileDb/FileDb.dll b/FileDbCache/FileDb/FileDb.dll deleted file mode 100644 index 794da39c7ef1f166b2a8b252ec7e39f28474be04..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 87040 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

6{@B-5vu1F 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 P{=>5IU$y^XB=Elgt?r0t diff --git a/FileDbCache/FileDb/FileDb.xml b/FileDbCache/FileDb/FileDb.xml deleted file mode 100644 index c1440eb3..00000000 --- a/FileDbCache/FileDb/FileDb.xml +++ /dev/null @@ -1,1910 +0,0 @@ - - - - FileDb - - - -

- Represents an open FileDb database file. All of the FileDb classes/methods are re-entrant - - there is no need to syncronise access to the class objects by the calling application. - However you should use the try-finally pattern when you open a FileDb to ensure - prompt closing in the finally code block. - - - - - - Constructor for FileDb - - - - - - ToString override - returns the DB filename or a string indicating its a memory DB - - - - - - - Open the indicated database file. - If dbFileName is null an in-memory database will be created. - - The filename of the database file to open. - It can be a fully qualified path or, if no path is specified the current folder will be used. - Indicates whether to open read only or not - - - - - Open the indicated database file for encryption. Encryption is "all or nothing", - meaning all records are either encrypted or not. - If dbFileName is null an in-memory database will be created. - - The filename of the database file to open. - It can be a fully qualified path or, if no path is specified the current folder will be used. - A string value to use as the encryption key - Indicates whether to open read only or not - - - - - Close an open database. - - - - - - Create a new database file. If the file exists, it will be overwritten. - If dbFileName is null an in-memory database will be created. - - The full pathname of the file or null/empty to create a memory DB - Array of Fields for the new database. - - - - - Create a new database file. If the file exists, it will be overwritten. - If dbFileName is null an in-memory database will be created. - - The full pathname of the file or null/empty to create a memory DB - List of Fields for the new database. - - - - - Delete an existing database. - - The pathname of the file to delete. - TODO: make static - - - - Indicates if the DB filename's existence - - - True if the file exists, false otherwise - - - - - Start a transaction - a backup of the whole database file is made until the transaction is completed. - Be sure to call either CommitTrans or RollbackTrans so the backup can be disposed - - - - - - Commit the changes since the transaction was begun - - - - - - Roll back the changes since the transaction was begun - - - - - - Add a new record to the database using the name-value pairs in the FieldValues object. - Note that not all fields must be represented. Missing fields will be set to default - values (0, empty or null). Note that only Array datatypes can NULL. - - The name-value pairs to add. - The volatile index of the newly added record. - - - - - Return a Table of Records filtered by the filter parameter. - - A FilterExpression representing the desired filter. - A new Table with the requested Records - - - - - Return a Table of Records filtered by the filter parameter. Only the specified Fields - will be in the Table. - - A FilterExpression representing the desired filter. - The desired fields to be in the returned Table - A new Table with the requested Records and Fields - - - - - Return a Table of Records filtered by the filter parameter. Only the specified Fields - will be in the Table. - - A FilterExpression representing the desired filter. - The desired fields to be in the returned Table - A list of one or more fields to order the returned table by, - or null for default order. If an orderByField is prefixed with "!", that field will sorted - in reverse order. - A new Table with the requested Records and Fields ordered by the specified fields. - - - - - Get all records matching the search expression in the indicated order, if any. - - Represents a single search expression, such as ID = 3 - The list of fields to return or null for all fields - If true, an additional Field named "index" will be returned - which is the ordinal index of the Record in the database, which can be used in - GetRecordByIndex and UpdateRecordByIndex. - A list of one or more fields to order the returned table by, - or null for default order. If an orderByField is prefixed with "!", that field will sorted - in reverse order. - A new Table with the requested Records and Fields - - - - - Return a Table of Records filtered by the filter parameter. - - A FilterExpressionGroup representing the desired filter. - A new Table with the requested Records - - - - - Return a Table of Records filtered by the filter parameter. Only the specified Fields - will be in the Table. - - A FilterExpression representing the desired filter. - The desired fields to be in the returned Table - A new Table with the requested Records and Fields - - - - - Return a Table of Records filtered by the filter parameter. Only the specified Fields - will be in the Table. - - A FilterExpression representing the desired filter. - The desired fields to be in the returned Table - A list of one or more fields to order the returned table by, - or null for default order. If an orderByField is prefixed with "!", that field will sorted - in reverse order. - A new Table with the requested Records and Fields in the specified order - - - - - Get all records matching the FilterExpressionGroup in the indicated order, if any. - - Represents a compound search expression, such as FirstName = "John" AND LastName = "Smith" - The list of fields to return or null for all fields - Specify whether to include the record index as one of the Fields - A list of one or more fields to order the returned table by, - or null for default order. If an orderByField is prefixed with "!", that field will sorted - in reverse order. - A new Table with the requested Records and Fields - - - - - Return a Table of Records filtered by the filter parameter. - - A string representing the desired filter, eg. LastName = 'Fuller' - A new Table with the requested Records - - - - - Return a Table of Records filtered by the filter parameter. Only the specified Fields - will be in the Table. - - A string representing the desired filter, eg. LastName = 'Fuller' - The desired fields to be in the returned Table - A new Table with the requested Records and Fields - - - - - Return a Table of Records filtered by the filter parameter. Only the specified Fields - will be in the Table. - - A string representing the desired filter, eg. LastName = 'Fuller' - The desired fields to be in the returned Table - A list of one or more fields to order the returned table by, - or null for default order. If an orderByField is prefixed with "!", that field will sorted - in reverse order. - A new Table with the requested Records and Fields ordered by the specified list - - - - - Return a Table of Records filtered by the filter parameter. - - A string representing the desired filter, eg. LastName = 'Fuller' - The desired fields to be in the returned Table - If true, an additional Field named "index" will be returned - which is the ordinal index of the Record in the database, which can be used in - GetRecordByIndex and UpdateRecordByIndex - A list of one or more fields to order the returned table by, - or null for default order. If an orderByField is prefixed with "!", that field will sorted - in reverse order - A new Table with the requested Records and Fields - - - - - Return all records in the database (table). - - A table containing all Records and Fields. - - - - - Return all records in the database (table). - - The list of Fields to return or null for all Fields - A table containing all rows. - - - - - Return all records in the database (table). - - The list of fields to return or null for all Fields - A list of one or more fields to order the returned table by, - or null for default order - A table containing all rows. - - - - - Return all records in the database (table). - - Specify whether to include the Record index as one of the Fields - A table containing all rows. - - - - - Return all records in the database (table). - - The list of fields to return or null for all fields - Specify whether to include the record index as one of the Fields - A list of one or more fields to order the returned table by, - or null for default order - A table containing all Records and the specified Fields. - - - - - Sometimes you may need to get an empty table just for the field definitions. - Use this method because its much more efficient than using a contrived filter - which is designed to return no results. - - An empty table containing all fields - - - - - Returns a single Record object at the current location. Meant to be used ONLY in conjunction - with the MoveFirst/MoveNext methods. - - The list of fields to return or null for all fields - Specify whether to include the record index as one of the Fields - A Record object or null - - - - - - Returns a single Record object specified by the index. - - The index of the record to return. This value can be obtained from - Record returning queries by specifying true for the includeIndex parameter. - The list of fields to return or null for all fields - A Record object or null - - - - - Returns a single Record object specified by the primary key value or record number. - - The primary key value. For databases without a primary key, - 'key' is the zero-based record number in the table. - The list of fields to return or null for all fields - Specify whether to include the record index as one of the Fields - A Record object or null - - - - - Update the record at the indicated index. To get the index, you would need to first - get a record from the database then use the index field from it. The index is only - valid until a database operation which would invalidate it, such as adding/deleting - a record, or changing the value of a primary key. - - The record values to update - The index of the record to update - - - - - Update the record with the indicated primary key value. - - The record values to update - The primary key value of the record to update - - - - - Update all records which match the search criteria using the values in record. - - The search expression, e.g. ID = 100 - A list of name-value pairs to use to update the matching records - The number of records which were updated. - - - - - Update all records which match the compound search criteria using the values in record. - - The compound search expression, e.g. FirstName = "John" AND LastName = "Smith" - A list of name-value pairs to use to update the matching records - The number of records which were updated. - - - - - Update all records which match the filter expression using the values in record. - - The filter to use, eg. "~LastName = 'peacock' OR ~FirstName = 'nancy'". - This filter string will be parsed using FilterExpressionGroup.Parse. - A list of name-value pairs to use to update the matching records - The number of records which were updated. - - - - - Delete all records in the database - - The number of records deleted - - - - - Delete the record at the specified index. You would normally get the index from a previous - query. This index is only valid until a record has been deleted. - - The zero-based index of the record to delete. - true if the record was deleted, false otherwise - - - - - Delete the record with the specified primary key value - - The primary key value of the record to delete - true if the record was deleted, false otherwise - - - - - Delete all records which match the search criteria. - - The search expression, e.g. ID = 100 - The number of records deleted - - - - - Delete all records which match the compound search criteria. - - The compound search expression, e.g. FirstName = "John" AND LastName = "Smith" - The number of records deleted - - - - - Delete all records which match the filter criteria. - - The filter to use, eg. "~LastName = 'peacock' OR ~FirstName = 'nancy'". - This filter string will be parsed using FilterExpressionGroup.Parse. - The number of records deleted - - - - - Move to the first record in the index. Use this in conjunction with MoveNext and GetCurrentRecord - - - - - - Move to the next record in the index. Use this in conjunction with MoveFirst and GetCurrentRecord - - - - - Call this to remove deleted records from the file (compact). - - - - - - Call this to write the index and flush the stream buffer to disk. - Flushing will be done automatically if AutoFlush is On (and only writes the index - if necessary), whereas this call always writes the index. - You can use this to periodically write everything to disk rather than each time - as with AutoFlush. Flush is always called when the file is closed, however in that - case the index is only written if AutoFlush is set to Off. - - - - - - Call this method to reindex the database if your index file should be deleted or corrupted. - - - - - - Add the specified Field to the database. - - The new Field to add - A default value to use for the values of existing records for the new Field - - - - - Add the specified Field to the database. - - The new Fields to add - Default values to use for the values of existing records for the new Fields. - Can be null but if not then you must provide a value for each field in the Fields array - - - - - Delete the specified Field from the database. - - The name of the Field to delete - - - - - Delete the specified Fields from the database. - - The Fields to delete - - - - - Rename the specified Field. - - The name of the Field to rename - - - - - Used to set your own encryptor. Use this for cross-platform encryption scenarios, where you - have control over the encryption method being used. See the Windows Sample apps for an example. - - - - - - - Convienience method to encrypt a string value. You must first call SetEncryptor with an Encryptor. - - The string to encrypt - The encrypted value - - - - - Decrypt a string value. You must first call SetEncryptor with an Encryptor. - - The string to decrypt - The decrypted value - - - - - *** Only works on Windows platform. Use SetEncryptor to provide your own encryptor for cross platform databases *** - *** Do not use this method anymore *** - Allows you to set an encryption key after the database has been opened. You must set - the encryption key before reading or writing to the database. Encryption is "all or nothing", - meaning all records are either encrypted or not. - - A string value to use as the encryption key - - - - Return a List of custom objects filtered by the filter parameter. - - A FilterExpression representing the desired filter. - A new List of custom objects with the requested Records - - - - - Return a List of custom objects filtered by the filter parameter. Only the specified Fields - will be in the Table. - - A FilterExpression representing the desired filter. - The desired fields to be in the returned Table - A new List of custom objects with the requested Records and Fields - - - - - Return a List of custom objects filtered by the filter parameter. Only the specified Fields - will be in the Table. - - A FilterExpression representing the desired filter. - The desired fields to be in the returned Table - A list of one or more fields to order the returned table by, - or null for default order. If an orderByField is prefixed with "!", that field will sorted - in reverse order. - A new List of custom objects with the requested Records and Fields ordered by the specified fields. - - - - - Get all records matching the search expression in the indicated order, if any. - - Represents a single search expression, such as ID = 3 - The list of fields to return or null for all fields - If true, an additional Field named "index" will be returned - which is the ordinal index of the Record in the database, which can be used in - GetRecordByIndex and UpdateRecordByIndex. - A list of one or more fields to order the returned table by, - or null for default order. If an orderByField is prefixed with "!", that field will sorted - in reverse order. - A new List of custom objects with the requested Records and Fields - - - - - Return a List of custom objects filtered by the filter parameter. - - A FilterExpressionGroup representing the desired filter. - A new List of custom objects with the requested Records - - - - - Return a List of custom objects filtered by the filter parameter. Only the specified Fields - will be in the Table. - - A FilterExpression representing the desired filter. - The desired fields to be in the returned Table - A new List of custom objects with the requested Records and Fields - - - - - Return a List of custom objects filtered by the filter parameter. Only the specified Fields - will be in the Table. - - A FilterExpression representing the desired filter. - The desired fields to be in the returned Table - A list of one or more fields to order the returned table by, - or null for default order. If an orderByField is prefixed with "!", that field will sorted - in reverse order. - A new List of custom objects with the requested Records and Fields in the specified order - - - - - Get all records matching the FilterExpressionGroup in the indicated order, if any. - - Represents a compound search expression, such as FirstName = "John" AND LastName = "Smith" - The list of fields to return or null for all fields - Specify whether to include the record index as one of the Fields - A list of one or more fields to order the returned table by, - or null for default order. If an orderByField is prefixed with "!", that field will sorted - in reverse order. - A new List of custom objects with the requested Records and Fields - - - - - Return a List of custom objects filtered by the filter parameter. - - A string representing the desired filter, eg. LastName = 'Fuller' - A new List of custom objects with the requested Records - - - - - Return a List of custom objects filtered by the filter parameter. Only the specified Fields - will be in the Table. - - A string representing the desired filter, eg. LastName = 'Fuller' - The desired fields to be in the returned Table - A new List of custom objects with the requested Records and Fields - - - - - Return a List of custom objects filtered by the filter parameter. Only the specified Fields - will be in the Table. - - A string representing the desired filter, eg. LastName = 'Fuller' - The desired fields to be in the returned Table - A list of one or more fields to order the returned table by, - or null for default order. If an orderByField is prefixed with "!", that field will sorted - in reverse order. - A new List of custom objects with the requested Records and Fields ordered by the specified list - - - - - Return a List of custom objects filtered by the filter parameter. - - A string representing the desired filter, eg. LastName = 'Fuller' - The desired fields to be in the returned Table - If true, an additional Field named "index" will be returned - which is the ordinal index of the Record in the database, which can be used in - GetRecordByIndex and UpdateRecordByIndex - A list of one or more fields to order the returned table by, - or null for default order. If an orderByField is prefixed with "!", that field will sorted - in reverse order - A new List of custom objects with the requested Records and Fields - - - - - Return all records in the database (table). - - A table containing all Records and Fields. - - - - - Return all records in the database (table). - - The list of Fields to return or null for all Fields - A table containing all rows. - - - - - Return all records in the database (table). - - The list of fields to return or null for all Fields - A list of one or more fields to order the returned table by, - or null for default order - A table containing all rows. - - - - - Return all records in the database (table). - - Specify whether to include the Record index as one of the Fields - A table containing all rows. - - - - - Return all records in the database (table). - - The list of fields to return or null for all fields - Specify whether to include the record index as one of the Fields - A list of one or more fields to order the returned table by, - or null for default order - A table containing all Records and the specified Fields. - - - - - Returns a single custom object at the current location. Meant to be used ONLY in conjunction - with the MoveFirst/MoveNext methods. - - The list of fields to return or null for all fields - Specify whether to include the record index as one of the Fields - A new object or null - - - - - - Returns a single custom object specified by the index. - - The index of the record to return. This value can be obtained from - Record returning queries by specifying true for the includeIndex parameter. - The list of fields to return or null for all fields - A new object or null - - - - - Returns a single custom object specified by the primary key value or record number. - - The primary key value. For databases without a primary key, - 'key' is the zero-based record number in the table. - The list of fields to return or null for all fields - Specify whether to include the record index as one of the Fields - A new object or null - - - - - Static event fired when a record has been updated. - - - - - Static event fired when a record has been inserted. - - - - - Static event fired when a record has been deleted. - - - - - Fired when a record has been updated. - - - - - - Fired when a record has been inserted. - - - - - - Fired when a record has been deleted. - - - - - - The full filename of the DB file - - - - - - A value which can be used to keep track of the database version for changes - - - - - The fields of the database (table). - - - - - - The number of records in the database (table). Doesn't include deleted records. - - - - - - The number of deleted records which not yet cleaned from the file. Call the - Clean method to remove all deleted records and compact the file. - - - - - - Configures autoclean. When an edit or delete is made, the - record is normally not removed from the data file - only the index. - After repeated edits/deletions, the data file may become very big with - deleted (non-removed) records. A cleanup is normally done with the - cleanup() method. Autoclean will do this automatically, keeping the - number of deleted records to under the threshold value. - To turn off autoclean, set threshold to a negative value. - - - - - - Specifies whether to automatically flush data buffers and write the index after each - operation in which the file was updated. When AutoFlush is not On, the index is not - written until the file is closed or Flush is called. - You can set AutoFlush to Off just before performing a bulk operation to dramatically - increase performance, then set it back On after. When you set it back On after it was - Off, everything is flushed immediately because the assumption is that it was needed, - so you don't need to call Flush in this case. - - Setting AutoFlush On is most useful for when you aren't able to guarantee that you will - be able to call Close before the program closes. This way the file won't become corrupt - in this case. - - - - - - Tests to see if a database is currently open. - - - - - - Allow ability to store meta data in the DB file. MetaData must be one of the supported - DataTypes: String, Byte, Int, UInt, Float, Double, Bool, DateTime and also Byte[] - - - - - - Handler for static DbRecordUpdated event. - - The name of the updated database - The record index - The fields and new values which were updated - - - - - Handler for static DbRecordAdded event. - - The name of the updated database - The record index - - - - Handler for static DbRecordDeleted event. - - The name of the updated database - The record index - - - - Handler for RecordUpdated event. - - The record index - The fields and new values which were updated - - - - - Handler for RecordAdded event. - - The record index - - - - - Handler for RecordDeleted event. - - The record index - - - - - Class uses the .NET AesManaged class for data encryption, but ONLY on the Windows platform - build...the PCL build just returns the same data without doing anything. This is because - encryption namespace isn't available for PCLs. In this case, create your own Encryptor - class using the IEncryptor interface and set it into the FileDb object via SetEncryptor. - - - - - - Constructor taking a key (password) and salt as a string - - - - - - - - Encrypt the passed byte array - - The data to encrypt - The encrypted data - - - - - Decrypt the passed byte array - - The data to decrypt - The decrypted data - - - - - Specifies the data type for database Fields - - - - - - Specifies the type of match for FilterExpressions with String data types - - - - - Specifies the comparison operator to use for FilterExpressions - - - - - Boolean operands to use to join FilterExpressions - - - - - Constructor - - - - - Open the database files - - - - - - - - Flushes the Stream and detaches it, rendering this FileDb closed - - - - - ---------------------------------------------------------------------------------------- - - record must have all fields - - - - - ---------------------------------------------------------------------------------------- - - record must have all fields - - - - - - Configures autoclean. When an edit or delete is made, the - record is normally not removed from the data file - only the index. - After repeated edits/deletions, the data file may become very big with - deleted (non-removed) records. A cleanup is normally done with the - cleanup() method. Autoclean will do this automatically, keeping the - number of deleted records to under the threshold value. - To turn off autoclean, set threshold to a negative value. - - number of deleted records to have at any one time - - - - ---------------------------------------------------------------------------------------- - - Read all records to create new index. - - - - - - Remove all deleted records - - - - - - Removes an entry from the database INDEX only - it appears - deleted, but the actual data is only removed from the file when a - cleanup() is called. - - Int32 or string primary key used to identify record to remove. For - databases without primary keys, it is the record number (zero based) in - the table. - true if a record was removed, false otherwise - - - - - Removes an entry from the database INDEX only - it appears - deleted, but the actual data is only removed from the file when a - cleanup() is called. - - The record number (zero based) in the table to remove - true on success, false otherwise - - - - - Removes entries from the database INDEX only, based on the - result of a regular expression match on a given field - records appear - deleted, but the actual data is only removed from the file when a - cleanup() is called. - - - number of records removed - - - - move to the first index position - - - - - - Move the current index position to the next database item. - - true if advanced to a new item, false if there are none left - - - - - Return the current record in the database. Note that the current iterator pointer is not moved in any way. - - - - - - - retrieves a record based on the specified key - - primary key used to identify record to retrieve. For - databases without primary keys, it is the record number (zero based) in - the table. - - if true, an extra field called 'IFIELD' will - be added to each record returned. It will contain an Int32 that specifies - the original position in the database (zero based) that the record is - positioned. It might be useful when an orderby is used, and a future - operation on a record is required, given it's index in the table. - record if found, or false otherwise - - - - - retrieves a record based on the record number in the table - (zero based) - - zero based record number to retrieve - - - - - - - - Searches the database for an item, and returns true if found, false otherwise. - - rimary key of record to search for, or the record - number (zero based) for databases without a primary key - true if found, false otherwise - - - - - Returns the number of records in the database - - the number of records in the database - - - - - Returns the number of deleted records in the database, that would be removed if cleanup() is called. - - the number of deleted records in the database - - - - - Returns the current database schema in the same form - as that used in the parameter for the create(...) method. - - - - - - - Flush the in-memory buffers to disk - - - - - - Helper - - - - - - - - Helper - - - - - - - - Use this version if you will need to add/remove indices - - - - - - function to write the index values. We assume the - database has been locked before calling this function. - - - - - - - - - - - to keep track of null fields in written record - - - - - - Use this version only if all of the fields are present and in the correct order in the array - - - - - - - - - Use this version only if all of the fields are present and in the correct order in the array - - - - - - - Write a single field to the file - - - - - - - - ------------------------------------------------------------------------------ - - Private function to perform a binary search - - file offsets into the .dat file, it must be ordered - by primary key. - the left most index to start searching from - the right most index to start searching from - the search target we're looking for - -[insert pos+1] when not found, or the array index+1 - when found. Note that we don't return the normal position, because we - can't differentiate between -0 and +0. - - - - - Helper - - - - - - - - Private function to read a record from the database - - - - - - size does not include the 4 byte record length, but only the total size of the fields - - - - - - - - - function to read a record KEY from the database. Note - that this function relies on the fact that they key is ALWAYS the first - item in the database record as stored on disk. - - - - - - - - - Reads a data type from a file. Note that arrays can only - consist of other arrays, ints, and strings. - - - - - - - - - Write the database schema and other meta information. - - - - - - - Helper - - - - - - - - Use this class for single field searches. - - - - - - Create a FilterExpression with the indicated values - - The name of the Field to filter on - The Field value to filter on - The Equality operator to use in the value comparison - - - - - Create a FilterExpression with the indicated values - - The name of the Field to filter on - The Field value to filter on - The Equality operator to use in the value comparison - The match type, eg. MatchType.Exact - - - - - Create a FilterExpression with the indicated values - - The name of the Field to filter on - The Field value to filter on - The Equality operator to use in the value comparison - The match type, eg. MatchType.Exact - Operator negation - - - - - Parse the expression string to create a FilterExpressionGroup representing a simple expression. - - The string expression. Example: LastName = 'Fuller' - A new FilterExpression representing the simple expression - - - - - Utility method to transform a filesystem wildcard pattern into a regex pattern - eg. december* or mary? - - - - - - - - Create a FilterExpression of type "IN". This type is a HashSet of the values which will be used - to filter the query. - - The name of the Field which will be used in the FilterExpressions - A Table to use to build the IN FilterExpressions - The name of the Field in the Table which holds the value to be used to build the IN FilterExpressions - A new FilterExpression - - - - - Create a FilterExpression of type "IN". This type is a HashSet of the values which will be used - to filter the query. - - The name of the Field which will be used in the FilterExpressions - A List of custom objects to use to build the IN FilterExpression - The name of the Property of the custom class which holds the value to be - used to build the IN FilterExpression - A new FilterExpression - - - - - Create a FilterExpression of type "IN". This type is a HashSet of the values which will be used - to filter the query. - - The name of the Field which will be used in the FilterExpressions - A List of strings to use to build the IN FilterExpression - A new FilterExpression - - - - - Create a FilterExpression of type "IN". This type is a HashSet of the values which will be used - to filter the query. - - The name of the Field which will be used in the FilterExpressions - A List of strings to use to build the IN FilterExpression - A new FilterExpression - - - - - Use this class to group FilterExpression and FilterExpressionGroup to form compound search expressions. - All expressions in the group will be evaluated by the same boolean And/Or operation. Use multiple - FilterExpressionGroups to form any combination of And/Or logic. - - - - - - Parse the expression string to create a FilterExpressionGroup representing a compound expression. - - The string compound expression. Example: (FirstName ~= 'andrew' OR FirstName ~= 'nancy') AND LastName = 'Fuller' - A new FilterExpressionGroup representing the compound expression - - - - - Summary description for HexEncoding. - - - - - Creates a byte array from the hexadecimal string. Each two characters are combined - to create one byte. First two hexadecimal characters become first byte in returned array. - Non-hexadecimal characters are ignored. - - string to convert to byte array - number of characters in string ignored - byte array, in the same left-to-right order as the hexString - - - - Determines if given string is in proper hexadecimal string format - - - - - - - Returns true is c is a hexadecimal digit (A-F, a-f, 0-9) - - Character to test - true if hex digit, false if not - - - - Converts 1 or 2 character string into equivalant byte value - - 1 or 2 character string - byte - - - - Represents a column of the database (table). - - - - - Use this constructor when creating a new database. The ordinal index of the field will be the - order it was added to the field list, unless a primary key field is specified and wasn't the - first in the list. In this case the primary key field will be moved to the first in the list - so that its always first. - - The name of the field - The data type of the field - - - - - Use this constructor when you need to create a Records list manually rather than - using one retured from a query. In this case, you must set the field ordinal index - for each field, starting at zero. - - The name of the field - The data type of the field - The zero-based ordinal index of the field - - - - - Clone this Field - - A new Field with the same values - - - - The name of the field. - - - - - The type of the field. - - - - - The zero-based ordinal index of the field. - - - - - Indicates if this is the one and only primary key field - - - - - Indicate if this is an Array type field - - - - - Used for auto-increment fields. Set to the number which you want incrementing to begin. - Leave it null if not an auto-increment field. - - - - - Returns true if this is an auto-increment field, false otherwise - - - - - Comment for the field - - - - - User property to associate a value with this Field - - - - - Represents data for a row, a Record consists of name-value pairs. - Used when adding data to the database and by the Record object - to store data returned from queries. - - - - - Represents a single row returned from a query. It will - contain one or more fields of the database (table). The last column may be the index of the row (if requested), - which is the zero-based position of the record in the index. If there is no primary key specified for - the database (table), then the index is the record number in the order in which the row was added to the database. - - - - - - Create a Record object with the indicated Fields and values. If creating a list of Record objects - (for a Records list) be sure to use the same Fields list for each Record. - - List of Field objects - Array of values. Each value will be converted to the Field type if possible. - - - - - Create a Record object with the indicated Fields and values. If creating a list of Record objects - (for a Records list) be sure to use the same Fields list for each Record. - - List of Field objects - Array of values. Each value will be converted to the Field type if possible. - - - - - Tests to see if the indicated field is in this Record - - - true if the field is in this Record - - - - - Return the Typed field value. - - The name of the field - The Type field value - - - - - Return the integer field value. - - The name of the field - The integer field value - - - - - Return the integer field value. - - The ordinal index of the field - The integer field value - - - - - Return the unsigned integer field value. - - The name of the field - The unsigned integer field value - - - - - Return the unsigned integer field value. - - The ordinal index of the field - The unsigned integer field value - - - - - Return the String field value. - - The name of the field - The String field value - - - - - Return the String field value. - - The ordinal index of the field - The String field value - - - - - Return the Byte field value. - - The name of the field - The Byte field value - - - - - Return the Byte field value. - - The ordinal index of the field - The Byte field value - - - - - Return the Single field value. - - The name of the field - The Single field value - - - - - Return the Single field value. - - The ordinal index of the field - The Single field value - - - - - Return the Double field value. - - The name of the field - The Double field value - - - - - Return the Decimal field value. - - The ordinal index of the field - The Decimal field value - - - - - Return the Decimal field value. - - The name of the field - The Decimal field value - - - - - Return the Double field value. - - The ordinal index of the field - The Double field value - - - - - Return the Boolean field value. - - The name of the field - The Boolean field value - - - - - Return the Boolean field value. - - The ordinal index of the field - The Boolean field value - - - - - Return the DateTime field value. - - The name of the field - The DateTime field value - - - - - Return the DateTime field value. - - The ordinal index of the field - The DateTime field value - - - - - The number of fields in the Record - - - - - - A property which is used for integrating with the binding framework. - - - - - - Used by the Record class for enumerating in foreach contructs - - - - - - A List of Records - - - - - - A list of Fields - - - - - - Represents a data table returned from a query. A table is made up of Fields and Records. - - - - - - Create a table with the indicated Fields. - - The Fields list to use (a copy is made) - - - - - Create a table with the indicated Fields and records. If copyFields is true, a new - Fields list is created and a copy of each field is made and its ordinal adjusted. - Otherwise the original Fields object is adopted. You should pass false for copyFields - only if you created the Fields list and its Field objects yourself. - - The Fields list to use - Indicates whether to make a copy of the Fields object and each Field. - - - - - Create a table with the indicated Fields and records. If copyFields is true, a new - Fields list is created and a copy of each field is made and its ordinal adjusted. - Otherwise the original Fields object is adopted. You should pass false for copyFields - only if you created the Fields list and its Field objects yourself. - - The Fields list to use - The record data - Indicates whether to make a copy of the Fields object and each Field. - - - - - Create a table with the indicated Fields and records. If copyFields is true, a new - Fields list is created and a copy of each field is made and its ordinal adjusted. - Otherwise the original Fields object is adopted. You should pass false for copyFields - only if you created the Fields list and its Field objects yourself and the Fields in - the Record objects match the data in the Record. - - The Fields list to use - The record data - Indicates whether to make a copy of the Fields object and each Field. - - - - - Add a new Record to this Table with all null values. - - - - - - - Add a new Record to this Table with the specfied values, which must be in the order - of their corresponding fields. - - - - - - - Add a new Record to this Table with the FieldValues - - - - - - - - Save this Table to the indicated file as a new database. If the file exists - it will be overwritten. The new database will be just as if you had created - it from scratch and populated it with the Table data. - - The full path and filename of the new database - - - - - Return a Table of Records filtered by the filter parameter. - - A string representing the desired filter, eg. LastName = 'Fuller' - A new Table with the requested Records - - - - - Return a Table of Records filtered by the filter parameter. Only the specified Fields - will be in the Table. - - A string representing the desired filter, eg. LastName = 'Fuller' - The desired fields to be in the returned Table - A new Table with the requested Records and Fields - - - - - Return a Table of Records filtered by the filter parameter. Only the specified Fields - will be in the Table. - - A string representing the desired filter, eg. LastName = 'Fuller' - The desired fields to be in the returned Table - A list of one or more fields to order the returned table by, - or null for default order. If an orderByField is prefixed with "!", that field will sorted - in reverse order. - A new Table with the requested Records and Fields ordered by the specified list - - - - - Return a Table of Records filtered by the filter parameter. - - A FilterExpression representing the desired filter. - A new Table with the requested Records - - - - - Return a Table of Records filtered by the filter parameter. Only the specified Fields - will be in the Table. - - A FilterExpression representing the desired filter. - The desired fields to be in the returned Table - A new Table with the requested Records and Fields - - - - - Return a Table of Records filtered by the filter parameter. Only the specified Fields - will be in the Table. - - A FilterExpression representing the desired filter. - The desired fields to be in the returned Table - A list of one or more fields to order the returned table by, - or null for default order. If an orderByField is prefixed with "!", that field will sorted - in reverse order. - A new Table with the requested Records and Fields ordered by the specified fields. - - - - - Return a Table of Records filtered by the filter parameter. - - A FilterExpressionGroup representing the desired filter. - A new Table with the requested Records - - - - - Return a Table of Records filtered by the filter parameter. Only the specified Fields - will be in the Table. - - A FilterExpression representing the desired filter. - The desired fields to be in the returned Table - A new Table with the requested Records and Fields - - - - - Return a Table of Records filtered by the filter parameter. Only the specified Fields - will be in the Table. - - A FilterExpression representing the desired filter. - The desired fields to be in the returned Table - A list of one or more fields to order the returned table by, - or null for default order. If an orderByField is prefixed with "!", that field will sorted - in reverse order. - A new Table with the requested Records and Fields in the specified order - - - - - The Fields of the Table - - - - - - A simple class used to communicate property value changes to a Record. - Used by WPF databinding. - - - - - diff --git a/FileDbCache/FileDb/FileDbPcl.dll b/FileDbCache/FileDb/FileDbPcl.dll deleted file mode 100644 index 4a129a34de63fef1a16ac2593f81c573e5d50f46..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 80384 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 - - - FileDbPcl - - - - - Represents an open FileDb database file. All of the FileDb classes/methods are re-entrant - - there is no need to syncronise access to the class objects by the calling application. - However you should use the try-finally pattern when you open a FileDb to ensure - prompt closing in the finally code block. - - - - - - Constructor for FileDb - - - - - - ToString override - returns the DB filename or a string indicating its a memory DB - - - - - - - Open with an existing database stream - - The database stream to use - normally a FileStream - - - - - Close an open database. - - - - - - Create a new database using the passed stream, or if null and in-memory DB - - The stream to use or null to create a memory DB - Array of Fields for the new database. - - - - - Create a new database using the passed stream, or if null and in-memory DB - - The stream to use or null to create a memory DB - List of Fields for the new database. - - - - - Start a transaction - a backup of the whole database file is made until the transaction is completed. - Be sure to call either CommitTrans or RollbackTrans so the backup can be disposed - - - - - - Commit the changes since the transaction was begun - - - - - - Roll back the changes since the transaction was begun - - - - - - Add a new record to the database using the name-value pairs in the FieldValues object. - Note that not all fields must be represented. Missing fields will be set to default - values (0, empty or null). Note that only Array datatypes can NULL. - - The name-value pairs to add. - The volatile index of the newly added record. - - - - - Return a Table of Records filtered by the filter parameter. - - A FilterExpression representing the desired filter. - A new Table with the requested Records - - - - - Return a Table of Records filtered by the filter parameter. Only the specified Fields - will be in the Table. - - A FilterExpression representing the desired filter. - The desired fields to be in the returned Table - A new Table with the requested Records and Fields - - - - - Return a Table of Records filtered by the filter parameter. Only the specified Fields - will be in the Table. - - A FilterExpression representing the desired filter. - The desired fields to be in the returned Table - A list of one or more fields to order the returned table by, - or null for default order. If an orderByField is prefixed with "!", that field will sorted - in reverse order. - A new Table with the requested Records and Fields ordered by the specified fields. - - - - - Get all records matching the search expression in the indicated order, if any. - - Represents a single search expression, such as ID = 3 - The list of fields to return or null for all fields - If true, an additional Field named "index" will be returned - which is the ordinal index of the Record in the database, which can be used in - GetRecordByIndex and UpdateRecordByIndex. - A list of one or more fields to order the returned table by, - or null for default order. If an orderByField is prefixed with "!", that field will sorted - in reverse order. - A new Table with the requested Records and Fields - - - - - Return a Table of Records filtered by the filter parameter. - - A FilterExpressionGroup representing the desired filter. - A new Table with the requested Records - - - - - Return a Table of Records filtered by the filter parameter. Only the specified Fields - will be in the Table. - - A FilterExpression representing the desired filter. - The desired fields to be in the returned Table - A new Table with the requested Records and Fields - - - - - Return a Table of Records filtered by the filter parameter. Only the specified Fields - will be in the Table. - - A FilterExpression representing the desired filter. - The desired fields to be in the returned Table - A list of one or more fields to order the returned table by, - or null for default order. If an orderByField is prefixed with "!", that field will sorted - in reverse order. - A new Table with the requested Records and Fields in the specified order - - - - - Get all records matching the FilterExpressionGroup in the indicated order, if any. - - Represents a compound search expression, such as FirstName = "John" AND LastName = "Smith" - The list of fields to return or null for all fields - Specify whether to include the record index as one of the Fields - A list of one or more fields to order the returned table by, - or null for default order. If an orderByField is prefixed with "!", that field will sorted - in reverse order. - A new Table with the requested Records and Fields - - - - - Return a Table of Records filtered by the filter parameter. - - A string representing the desired filter, eg. LastName = 'Fuller' - A new Table with the requested Records - - - - - Return a Table of Records filtered by the filter parameter. Only the specified Fields - will be in the Table. - - A string representing the desired filter, eg. LastName = 'Fuller' - The desired fields to be in the returned Table - A new Table with the requested Records and Fields - - - - - Return a Table of Records filtered by the filter parameter. Only the specified Fields - will be in the Table. - - A string representing the desired filter, eg. LastName = 'Fuller' - The desired fields to be in the returned Table - A list of one or more fields to order the returned table by, - or null for default order. If an orderByField is prefixed with "!", that field will sorted - in reverse order. - A new Table with the requested Records and Fields ordered by the specified list - - - - - Return a Table of Records filtered by the filter parameter. - - A string representing the desired filter, eg. LastName = 'Fuller' - The desired fields to be in the returned Table - If true, an additional Field named "index" will be returned - which is the ordinal index of the Record in the database, which can be used in - GetRecordByIndex and UpdateRecordByIndex - A list of one or more fields to order the returned table by, - or null for default order. If an orderByField is prefixed with "!", that field will sorted - in reverse order - A new Table with the requested Records and Fields - - - - - Return all records in the database (table). - - A table containing all Records and Fields. - - - - - Return all records in the database (table). - - The list of Fields to return or null for all Fields - A table containing all rows. - - - - - Return all records in the database (table). - - The list of fields to return or null for all Fields - A list of one or more fields to order the returned table by, - or null for default order - A table containing all rows. - - - - - Return all records in the database (table). - - Specify whether to include the Record index as one of the Fields - A table containing all rows. - - - - - Return all records in the database (table). - - The list of fields to return or null for all fields - Specify whether to include the record index as one of the Fields - A list of one or more fields to order the returned table by, - or null for default order - A table containing all Records and the specified Fields. - - - - - Sometimes you may need to get an empty table just for the field definitions. - Use this method because its much more efficient than using a contrived filter - which is designed to return no results. - - An empty table containing all fields - - - - - Returns a single Record object at the current location. Meant to be used ONLY in conjunction - with the MoveFirst/MoveNext methods. - - The list of fields to return or null for all fields - Specify whether to include the record index as one of the Fields - A Record object or null - - - - - - Returns a single Record object specified by the index. - - The index of the record to return. This value can be obtained from - Record returning queries by specifying true for the includeIndex parameter. - The list of fields to return or null for all fields - A Record object or null - - - - - Returns a single Record object specified by the primary key value or record number. - - The primary key value. For databases without a primary key, - 'key' is the zero-based record number in the table. - The list of fields to return or null for all fields - Specify whether to include the record index as one of the Fields - A Record object or null - - - - - Update the record at the indicated index. To get the index, you would need to first - get a record from the database then use the index field from it. The index is only - valid until a database operation which would invalidate it, such as adding/deleting - a record, or changing the value of a primary key. - - The record values to update - The index of the record to update - - - - - Update the record with the indicated primary key value. - - The record values to update - The primary key value of the record to update - - - - - Update all records which match the search criteria using the values in record. - - The search expression, e.g. ID = 100 - A list of name-value pairs to use to update the matching records - The number of records which were updated. - - - - - Update all records which match the compound search criteria using the values in record. - - The compound search expression, e.g. FirstName = "John" AND LastName = "Smith" - A list of name-value pairs to use to update the matching records - The number of records which were updated. - - - - - Update all records which match the filter expression using the values in record. - - The filter to use, eg. "~LastName = 'peacock' OR ~FirstName = 'nancy'". - This filter string will be parsed using FilterExpressionGroup.Parse. - A list of name-value pairs to use to update the matching records - The number of records which were updated. - - - - - Delete all records in the database - - The number of records deleted - - - - - Delete the record at the specified index. You would normally get the index from a previous - query. This index is only valid until a record has been deleted. - - The zero-based index of the record to delete. - true if the record was deleted, false otherwise - - - - - Delete the record with the specified primary key value - - The primary key value of the record to delete - true if the record was deleted, false otherwise - - - - - Delete all records which match the search criteria. - - The search expression, e.g. ID = 100 - The number of records deleted - - - - - Delete all records which match the compound search criteria. - - The compound search expression, e.g. FirstName = "John" AND LastName = "Smith" - The number of records deleted - - - - - Delete all records which match the filter criteria. - - The filter to use, eg. "~LastName = 'peacock' OR ~FirstName = 'nancy'". - This filter string will be parsed using FilterExpressionGroup.Parse. - The number of records deleted - - - - - Move to the first record in the index. Use this in conjunction with MoveNext and GetCurrentRecord - - - - - - Move to the next record in the index. Use this in conjunction with MoveFirst and GetCurrentRecord - - - - - Call this to remove deleted records from the file (compact). - - - - - - Call this to write the index and flush the stream buffer to disk. - Flushing will be done automatically if AutoFlush is On (and only writes the index - if necessary), whereas this call always writes the index. - You can use this to periodically write everything to disk rather than each time - as with AutoFlush. Flush is always called when the file is closed, however in that - case the index is only written if AutoFlush is set to Off. - - - - - - Call this method to reindex the database if your index file should be deleted or corrupted. - - - - - - Add the specified Field to the database. - - The new Field to add - A default value to use for the values of existing records for the new Field - - - - - Add the specified Field to the database. - - The new Fields to add - Default values to use for the values of existing records for the new Fields. - Can be null but if not then you must provide a value for each field in the Fields array - - - - - Delete the specified Field from the database. - - The name of the Field to delete - - - - - Delete the specified Fields from the database. - - The Fields to delete - - - - - Rename the specified Field. - - The name of the Field to rename - - - - - Used to set your own encryptor. Use this for cross-platform encryption scenarios, where you - have control over the encryption method being used. See the Windows Sample apps for an example. - - - - - - - Convienience method to encrypt a string value. You must first call SetEncryptor with an Encryptor. - - The string to encrypt - The encrypted value - - - - - Decrypt a string value. You must first call SetEncryptor with an Encryptor. - - The string to decrypt - The decrypted value - - - - - *** Only works on Windows platform. Use SetEncryptor to provide your own encryptor for cross platform databases *** - *** Do not use this method anymore *** - Allows you to set an encryption key after the database has been opened. You must set - the encryption key before reading or writing to the database. Encryption is "all or nothing", - meaning all records are either encrypted or not. - - A string value to use as the encryption key - - - - Return a List of custom objects filtered by the filter parameter. - - A FilterExpression representing the desired filter. - A new List of custom objects with the requested Records - - - - - Return a List of custom objects filtered by the filter parameter. Only the specified Fields - will be in the Table. - - A FilterExpression representing the desired filter. - The desired fields to be in the returned Table - A new List of custom objects with the requested Records and Fields - - - - - Return a List of custom objects filtered by the filter parameter. Only the specified Fields - will be in the Table. - - A FilterExpression representing the desired filter. - The desired fields to be in the returned Table - A list of one or more fields to order the returned table by, - or null for default order. If an orderByField is prefixed with "!", that field will sorted - in reverse order. - A new List of custom objects with the requested Records and Fields ordered by the specified fields. - - - - - Get all records matching the search expression in the indicated order, if any. - - Represents a single search expression, such as ID = 3 - The list of fields to return or null for all fields - If true, an additional Field named "index" will be returned - which is the ordinal index of the Record in the database, which can be used in - GetRecordByIndex and UpdateRecordByIndex. - A list of one or more fields to order the returned table by, - or null for default order. If an orderByField is prefixed with "!", that field will sorted - in reverse order. - A new List of custom objects with the requested Records and Fields - - - - - Return a List of custom objects filtered by the filter parameter. - - A FilterExpressionGroup representing the desired filter. - A new List of custom objects with the requested Records - - - - - Return a List of custom objects filtered by the filter parameter. Only the specified Fields - will be in the Table. - - A FilterExpression representing the desired filter. - The desired fields to be in the returned Table - A new List of custom objects with the requested Records and Fields - - - - - Return a List of custom objects filtered by the filter parameter. Only the specified Fields - will be in the Table. - - A FilterExpression representing the desired filter. - The desired fields to be in the returned Table - A list of one or more fields to order the returned table by, - or null for default order. If an orderByField is prefixed with "!", that field will sorted - in reverse order. - A new List of custom objects with the requested Records and Fields in the specified order - - - - - Get all records matching the FilterExpressionGroup in the indicated order, if any. - - Represents a compound search expression, such as FirstName = "John" AND LastName = "Smith" - The list of fields to return or null for all fields - Specify whether to include the record index as one of the Fields - A list of one or more fields to order the returned table by, - or null for default order. If an orderByField is prefixed with "!", that field will sorted - in reverse order. - A new List of custom objects with the requested Records and Fields - - - - - Return a List of custom objects filtered by the filter parameter. - - A string representing the desired filter, eg. LastName = 'Fuller' - A new List of custom objects with the requested Records - - - - - Return a List of custom objects filtered by the filter parameter. Only the specified Fields - will be in the Table. - - A string representing the desired filter, eg. LastName = 'Fuller' - The desired fields to be in the returned Table - A new List of custom objects with the requested Records and Fields - - - - - Return a List of custom objects filtered by the filter parameter. Only the specified Fields - will be in the Table. - - A string representing the desired filter, eg. LastName = 'Fuller' - The desired fields to be in the returned Table - A list of one or more fields to order the returned table by, - or null for default order. If an orderByField is prefixed with "!", that field will sorted - in reverse order. - A new List of custom objects with the requested Records and Fields ordered by the specified list - - - - - Return a List of custom objects filtered by the filter parameter. - - A string representing the desired filter, eg. LastName = 'Fuller' - The desired fields to be in the returned Table - If true, an additional Field named "index" will be returned - which is the ordinal index of the Record in the database, which can be used in - GetRecordByIndex and UpdateRecordByIndex - A list of one or more fields to order the returned table by, - or null for default order. If an orderByField is prefixed with "!", that field will sorted - in reverse order - A new List of custom objects with the requested Records and Fields - - - - - Return all records in the database (table). - - A table containing all Records and Fields. - - - - - Return all records in the database (table). - - The list of Fields to return or null for all Fields - A table containing all rows. - - - - - Return all records in the database (table). - - The list of fields to return or null for all Fields - A list of one or more fields to order the returned table by, - or null for default order - A table containing all rows. - - - - - Return all records in the database (table). - - Specify whether to include the Record index as one of the Fields - A table containing all rows. - - - - - Return all records in the database (table). - - The list of fields to return or null for all fields - Specify whether to include the record index as one of the Fields - A list of one or more fields to order the returned table by, - or null for default order - A table containing all Records and the specified Fields. - - - - - Returns a single custom object at the current location. Meant to be used ONLY in conjunction - with the MoveFirst/MoveNext methods. - - The list of fields to return or null for all fields - Specify whether to include the record index as one of the Fields - A new object or null - - - - - - Returns a single custom object specified by the index. - - The index of the record to return. This value can be obtained from - Record returning queries by specifying true for the includeIndex parameter. - The list of fields to return or null for all fields - A new object or null - - - - - Returns a single custom object specified by the primary key value or record number. - - The primary key value. For databases without a primary key, - 'key' is the zero-based record number in the table. - The list of fields to return or null for all fields - Specify whether to include the record index as one of the Fields - A new object or null - - - - - Static event fired when a record has been updated. - - - - - Static event fired when a record has been inserted. - - - - - Static event fired when a record has been deleted. - - - - - Fired when a record has been updated. - - - - - - Fired when a record has been inserted. - - - - - - Fired when a record has been deleted. - - - - - - The full filename of the DB file - - - - - - A value which can be used to keep track of the database version for changes - - - - - The fields of the database (table). - - - - - - The number of records in the database (table). Doesn't include deleted records. - - - - - - The number of deleted records which not yet cleaned from the file. Call the - Clean method to remove all deleted records and compact the file. - - - - - - Configures autoclean. When an edit or delete is made, the - record is normally not removed from the data file - only the index. - After repeated edits/deletions, the data file may become very big with - deleted (non-removed) records. A cleanup is normally done with the - cleanup() method. Autoclean will do this automatically, keeping the - number of deleted records to under the threshold value. - To turn off autoclean, set threshold to a negative value. - - - - - - Specifies whether to automatically flush data buffers and write the index after each - operation in which the file was updated. When AutoFlush is not On, the index is not - written until the file is closed or Flush is called. - You can set AutoFlush to Off just before performing a bulk operation to dramatically - increase performance, then set it back On after. When you set it back On after it was - Off, everything is flushed immediately because the assumption is that it was needed, - so you don't need to call Flush in this case. - - Setting AutoFlush On is most useful for when you aren't able to guarantee that you will - be able to call Close before the program closes. This way the file won't become corrupt - in this case. - - - - - - Tests to see if a database is currently open. - - - - - - Allow ability to store meta data in the DB file. MetaData must be one of the supported - DataTypes: String, Byte, Int, UInt, Float, Double, Bool, DateTime and also Byte[] - - - - - - Handler for static DbRecordUpdated event. - - The name of the updated database - The record index - The fields and new values which were updated - - - - - Handler for static DbRecordAdded event. - - The name of the updated database - The record index - - - - Handler for static DbRecordDeleted event. - - The name of the updated database - The record index - - - - Handler for RecordUpdated event. - - The record index - The fields and new values which were updated - - - - - Handler for RecordAdded event. - - The record index - - - - - Handler for RecordDeleted event. - - The record index - - - - - Class uses the .NET AesManaged class for data encryption, but ONLY on the Windows platform - build...the PCL build just returns the same data without doing anything. This is because - encryption namespace isn't available for PCLs. In this case, create your own Encryptor - class using the IEncryptor interface and set it into the FileDb object via SetEncryptor. - - - - - - Specifies the data type for database Fields - - - - - - Specifies the type of match for FilterExpressions with String data types - - - - - Specifies the comparison operator to use for FilterExpressions - - - - - Boolean operands to use to join FilterExpressions - - - - - Constructor - - - - - Open the database files - - - - - - - - Flushes the Stream and detaches it, rendering this FileDb closed - - - - - ---------------------------------------------------------------------------------------- - - record must have all fields - - - - - ---------------------------------------------------------------------------------------- - - record must have all fields - - - - - - Configures autoclean. When an edit or delete is made, the - record is normally not removed from the data file - only the index. - After repeated edits/deletions, the data file may become very big with - deleted (non-removed) records. A cleanup is normally done with the - cleanup() method. Autoclean will do this automatically, keeping the - number of deleted records to under the threshold value. - To turn off autoclean, set threshold to a negative value. - - number of deleted records to have at any one time - - - - ---------------------------------------------------------------------------------------- - - Read all records to create new index. - - - - - - Remove all deleted records - - - - - - Removes an entry from the database INDEX only - it appears - deleted, but the actual data is only removed from the file when a - cleanup() is called. - - Int32 or string primary key used to identify record to remove. For - databases without primary keys, it is the record number (zero based) in - the table. - true if a record was removed, false otherwise - - - - - Removes an entry from the database INDEX only - it appears - deleted, but the actual data is only removed from the file when a - cleanup() is called. - - The record number (zero based) in the table to remove - true on success, false otherwise - - - - - Removes entries from the database INDEX only, based on the - result of a regular expression match on a given field - records appear - deleted, but the actual data is only removed from the file when a - cleanup() is called. - - - number of records removed - - - - move to the first index position - - - - - - Move the current index position to the next database item. - - true if advanced to a new item, false if there are none left - - - - - Return the current record in the database. Note that the current iterator pointer is not moved in any way. - - - - - - - retrieves a record based on the specified key - - primary key used to identify record to retrieve. For - databases without primary keys, it is the record number (zero based) in - the table. - - if true, an extra field called 'IFIELD' will - be added to each record returned. It will contain an Int32 that specifies - the original position in the database (zero based) that the record is - positioned. It might be useful when an orderby is used, and a future - operation on a record is required, given it's index in the table. - record if found, or false otherwise - - - - - retrieves a record based on the record number in the table - (zero based) - - zero based record number to retrieve - - - - - - - - Searches the database for an item, and returns true if found, false otherwise. - - rimary key of record to search for, or the record - number (zero based) for databases without a primary key - true if found, false otherwise - - - - - Returns the number of records in the database - - the number of records in the database - - - - - Returns the number of deleted records in the database, that would be removed if cleanup() is called. - - the number of deleted records in the database - - - - - Returns the current database schema in the same form - as that used in the parameter for the create(...) method. - - - - - - - Flush the in-memory buffers to disk - - - - - - Helper - - - - - - - - Helper - - - - - - - - Use this version if you will need to add/remove indices - - - - - - function to write the index values. We assume the - database has been locked before calling this function. - - - - - - - - - - - to keep track of null fields in written record - - - - - - Use this version only if all of the fields are present and in the correct order in the array - - - - - - - - - Use this version only if all of the fields are present and in the correct order in the array - - - - - - - Write a single field to the file - - - - - - - - ------------------------------------------------------------------------------ - - Private function to perform a binary search - - file offsets into the .dat file, it must be ordered - by primary key. - the left most index to start searching from - the right most index to start searching from - the search target we're looking for - -[insert pos+1] when not found, or the array index+1 - when found. Note that we don't return the normal position, because we - can't differentiate between -0 and +0. - - - - - Helper - - - - - - - - Private function to read a record from the database - - - - - - size does not include the 4 byte record length, but only the total size of the fields - - - - - - - - - function to read a record KEY from the database. Note - that this function relies on the fact that they key is ALWAYS the first - item in the database record as stored on disk. - - - - - - - - - Reads a data type from a file. Note that arrays can only - consist of other arrays, ints, and strings. - - - - - - - - - Write the database schema and other meta information. - - - - - - - Helper - - - - - - - - Use this class for single field searches. - - - - - - Create a FilterExpression with the indicated values - - The name of the Field to filter on - The Field value to filter on - The Equality operator to use in the value comparison - - - - - Create a FilterExpression with the indicated values - - The name of the Field to filter on - The Field value to filter on - The Equality operator to use in the value comparison - The match type, eg. MatchType.Exact - - - - - Create a FilterExpression with the indicated values - - The name of the Field to filter on - The Field value to filter on - The Equality operator to use in the value comparison - The match type, eg. MatchType.Exact - Operator negation - - - - - Parse the expression string to create a FilterExpressionGroup representing a simple expression. - - The string expression. Example: LastName = 'Fuller' - A new FilterExpression representing the simple expression - - - - - Utility method to transform a filesystem wildcard pattern into a regex pattern - eg. december* or mary? - - - - - - - - Create a FilterExpression of type "IN". This type is a HashSet of the values which will be used - to filter the query. - - The name of the Field which will be used in the FilterExpressions - A Table to use to build the IN FilterExpressions - The name of the Field in the Table which holds the value to be used to build the IN FilterExpressions - A new FilterExpression - - - - - Create a FilterExpression of type "IN". This type is a HashSet of the values which will be used - to filter the query. - - The name of the Field which will be used in the FilterExpressions - A List of custom objects to use to build the IN FilterExpression - The name of the Property of the custom class which holds the value to be - used to build the IN FilterExpression - A new FilterExpression - - - - - Create a FilterExpression of type "IN". This type is a HashSet of the values which will be used - to filter the query. - - The name of the Field which will be used in the FilterExpressions - A List of strings to use to build the IN FilterExpression - A new FilterExpression - - - - - Create a FilterExpression of type "IN". This type is a HashSet of the values which will be used - to filter the query. - - The name of the Field which will be used in the FilterExpressions - A List of strings to use to build the IN FilterExpression - A new FilterExpression - - - - - Use this class to group FilterExpression and FilterExpressionGroup to form compound search expressions. - All expressions in the group will be evaluated by the same boolean And/Or operation. Use multiple - FilterExpressionGroups to form any combination of And/Or logic. - - - - - - Parse the expression string to create a FilterExpressionGroup representing a compound expression. - - The string compound expression. Example: (FirstName ~= 'andrew' OR FirstName ~= 'nancy') AND LastName = 'Fuller' - A new FilterExpressionGroup representing the compound expression - - - - - Summary description for HexEncoding. - - - - - Creates a byte array from the hexadecimal string. Each two characters are combined - to create one byte. First two hexadecimal characters become first byte in returned array. - Non-hexadecimal characters are ignored. - - string to convert to byte array - number of characters in string ignored - byte array, in the same left-to-right order as the hexString - - - - Determines if given string is in proper hexadecimal string format - - - - - - - Returns true is c is a hexadecimal digit (A-F, a-f, 0-9) - - Character to test - true if hex digit, false if not - - - - Converts 1 or 2 character string into equivalant byte value - - 1 or 2 character string - byte - - - - Represents a column of the database (table). - - - - - Use this constructor when creating a new database. The ordinal index of the field will be the - order it was added to the field list, unless a primary key field is specified and wasn't the - first in the list. In this case the primary key field will be moved to the first in the list - so that its always first. - - The name of the field - The data type of the field - - - - - Use this constructor when you need to create a Records list manually rather than - using one retured from a query. In this case, you must set the field ordinal index - for each field, starting at zero. - - The name of the field - The data type of the field - The zero-based ordinal index of the field - - - - - Clone this Field - - A new Field with the same values - - - - The name of the field. - - - - - The type of the field. - - - - - The zero-based ordinal index of the field. - - - - - Indicates if this is the one and only primary key field - - - - - Indicate if this is an Array type field - - - - - Used for auto-increment fields. Set to the number which you want incrementing to begin. - Leave it null if not an auto-increment field. - - - - - Returns true if this is an auto-increment field, false otherwise - - - - - Comment for the field - - - - - User property to associate a value with this Field - - - - - Represents data for a row, a Record consists of name-value pairs. - Used when adding data to the database and by the Record object - to store data returned from queries. - - - - - Represents a single row returned from a query. It will - contain one or more fields of the database (table). The last column may be the index of the row (if requested), - which is the zero-based position of the record in the index. If there is no primary key specified for - the database (table), then the index is the record number in the order in which the row was added to the database. - - - - - - Create a Record object with the indicated Fields and values. If creating a list of Record objects - (for a Records list) be sure to use the same Fields list for each Record. - - List of Field objects - Array of values. Each value will be converted to the Field type if possible. - - - - - Create a Record object with the indicated Fields and values. If creating a list of Record objects - (for a Records list) be sure to use the same Fields list for each Record. - - List of Field objects - Array of values. Each value will be converted to the Field type if possible. - - - - - Tests to see if the indicated field is in this Record - - - true if the field is in this Record - - - - - Return the Typed field value. - - The name of the field - The Type field value - - - - - Return the integer field value. - - The name of the field - The integer field value - - - - - Return the integer field value. - - The ordinal index of the field - The integer field value - - - - - Return the unsigned integer field value. - - The name of the field - The unsigned integer field value - - - - - Return the unsigned integer field value. - - The ordinal index of the field - The unsigned integer field value - - - - - Return the String field value. - - The name of the field - The String field value - - - - - Return the String field value. - - The ordinal index of the field - The String field value - - - - - Return the Byte field value. - - The name of the field - The Byte field value - - - - - Return the Byte field value. - - The ordinal index of the field - The Byte field value - - - - - Return the Single field value. - - The name of the field - The Single field value - - - - - Return the Single field value. - - The ordinal index of the field - The Single field value - - - - - Return the Double field value. - - The name of the field - The Double field value - - - - - Return the Decimal field value. - - The ordinal index of the field - The Decimal field value - - - - - Return the Decimal field value. - - The name of the field - The Decimal field value - - - - - Return the Double field value. - - The ordinal index of the field - The Double field value - - - - - Return the Boolean field value. - - The name of the field - The Boolean field value - - - - - Return the Boolean field value. - - The ordinal index of the field - The Boolean field value - - - - - Return the DateTime field value. - - The name of the field - The DateTime field value - - - - - Return the DateTime field value. - - The ordinal index of the field - The DateTime field value - - - - - The number of fields in the Record - - - - - - A property which is used for integrating with the binding framework. - - - - - - Used by the Record class for enumerating in foreach contructs - - - - - - A List of Records - - - - - - A list of Fields - - - - - - Represents a data table returned from a query. A table is made up of Fields and Records. - - - - - - Create a table with the indicated Fields. - - The Fields list to use (a copy is made) - - - - - Create a table with the indicated Fields and records. If copyFields is true, a new - Fields list is created and a copy of each field is made and its ordinal adjusted. - Otherwise the original Fields object is adopted. You should pass false for copyFields - only if you created the Fields list and its Field objects yourself. - - The Fields list to use - Indicates whether to make a copy of the Fields object and each Field. - - - - - Create a table with the indicated Fields and records. If copyFields is true, a new - Fields list is created and a copy of each field is made and its ordinal adjusted. - Otherwise the original Fields object is adopted. You should pass false for copyFields - only if you created the Fields list and its Field objects yourself. - - The Fields list to use - The record data - Indicates whether to make a copy of the Fields object and each Field. - - - - - Create a table with the indicated Fields and records. If copyFields is true, a new - Fields list is created and a copy of each field is made and its ordinal adjusted. - Otherwise the original Fields object is adopted. You should pass false for copyFields - only if you created the Fields list and its Field objects yourself and the Fields in - the Record objects match the data in the Record. - - The Fields list to use - The record data - Indicates whether to make a copy of the Fields object and each Field. - - - - - Add a new Record to this Table with all null values. - - - - - - - Add a new Record to this Table with the specfied values, which must be in the order - of their corresponding fields. - - - - - - - Add a new Record to this Table with the FieldValues - - - - - - - - Save this Table to the Stream as a new database. If the Stream is null - one will be created and it will be a memory DB. The new database will be just as if you had created - it from scratch and populated it with the Table data. - - The full path and filename of the new database - - - - - Return a Table of Records filtered by the filter parameter. - - A string representing the desired filter, eg. LastName = 'Fuller' - A new Table with the requested Records - - - - - Return a Table of Records filtered by the filter parameter. Only the specified Fields - will be in the Table. - - A string representing the desired filter, eg. LastName = 'Fuller' - The desired fields to be in the returned Table - A new Table with the requested Records and Fields - - - - - Return a Table of Records filtered by the filter parameter. Only the specified Fields - will be in the Table. - - A string representing the desired filter, eg. LastName = 'Fuller' - The desired fields to be in the returned Table - A list of one or more fields to order the returned table by, - or null for default order. If an orderByField is prefixed with "!", that field will sorted - in reverse order. - A new Table with the requested Records and Fields ordered by the specified list - - - - - Return a Table of Records filtered by the filter parameter. - - A FilterExpression representing the desired filter. - A new Table with the requested Records - - - - - Return a Table of Records filtered by the filter parameter. Only the specified Fields - will be in the Table. - - A FilterExpression representing the desired filter. - The desired fields to be in the returned Table - A new Table with the requested Records and Fields - - - - - Return a Table of Records filtered by the filter parameter. Only the specified Fields - will be in the Table. - - A FilterExpression representing the desired filter. - The desired fields to be in the returned Table - A list of one or more fields to order the returned table by, - or null for default order. If an orderByField is prefixed with "!", that field will sorted - in reverse order. - A new Table with the requested Records and Fields ordered by the specified fields. - - - - - Return a Table of Records filtered by the filter parameter. - - A FilterExpressionGroup representing the desired filter. - A new Table with the requested Records - - - - - Return a Table of Records filtered by the filter parameter. Only the specified Fields - will be in the Table. - - A FilterExpression representing the desired filter. - The desired fields to be in the returned Table - A new Table with the requested Records and Fields - - - - - Return a Table of Records filtered by the filter parameter. Only the specified Fields - will be in the Table. - - A FilterExpression representing the desired filter. - The desired fields to be in the returned Table - A list of one or more fields to order the returned table by, - or null for default order. If an orderByField is prefixed with "!", that field will sorted - in reverse order. - A new Table with the requested Records and Fields in the specified order - - - - - The Fields of the Table - - - - - - A simple class used to communicate property value changes to a Record. - Used by WPF databinding. - - - - - diff --git a/FileDbCache/FileDb/Help.html b/FileDbCache/FileDb/Help.html deleted file mode 100644 index c14fb2bd..00000000 --- a/FileDbCache/FileDb/Help.html +++ /dev/null @@ -1,983 +0,0 @@ - - - - - -FileDb Overview - - - - - -

Overview

-
-

FileDb is a simple database designed as a simple -local database solution for Xamarin Cross-Platform phone (Android, IOS, WinPhone) -or any .NET application.  FileDb is a No-SQL database - meant for use as a local data store for applications.  - Here are some important points about FileDb:

- -
    -
  • - Stores one table per file, including its index
  • -
  • - Extremely Lightweight - less than 50K
  • -
  • - Supports field types Int, UInt, Bool, String, Byte, - Float, Double and DateTime and also arrays of the same - types
  • -
  • - Index supports a single Primary Key field (optional)
  • -
  • - Compiled versions for Windows Phone - RT/PCL, - .NET
  • -
  • - FileDb is VERY FAST
  • -
  • - FileDb is FREE to use in your applications
  • -
  • - Use with LINQ to Objects to achieve full relational - capability
  • -
- -

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.

- -

LINQ + FileDb gives you full - relational database capability

-

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.)

-

FileDb also has a built-in - query filter parser so you can write SQL-like - filter expressions to make filtering data easy, like - this:

-
-

- - string filter = "FirstName IN ('Cindy', 'John') AND Age > 32"

-
-

Use FileDb in your .NET and mobile - applications where you need a searchable, updatable - local database.

-Use FileDb with Xamarin cross-platform app -development

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.

-

-FileDb Database Overview

- -

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.

-

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.

-

And FileDb supports using powerful Regular Expressions for -filtering.

-

FileDb supports AES encryption 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.

- -

FileDb is thread-safe for multithreading environments, so it can be accessed from -multiple threads at the same time without worrying about database corruption.

-

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).

-

FileDb Classes

-

The main FileDb classes are: FileDb, Table, -Field and Record.

- - -
  • FileDb: Represents a database file. All database operations are - initiated through this class.
  • - - -
  • Table: Represents a two - dimensional dataset returned from a query. A Table consists of Fields - and Records.
  • - - -
  • Field: Defines the - properties of the table column, such as Name and DataType.
  • - - -
  • Fields: A List of Field - objects.
  • -
  • - - - Record: A list of data objects represents a single row in a Table.  - Implements IEnumerable and the Data property which is used for DataBinding.
  • - - -
  • Records: A List of - Record objects.
  • - - -
  • FieldValues: A simple - Name/Value pair Dictionary. Use this class when adding and updating records.
  • - - -
  • FilterExpression: Used - to filter records for query, update and delete.
  • - - -
  • FilterExpressionGroup: - Used to create compound expressions by grouping FilterExpressions and - FilterExpressionGroups.
  • -
    -

    Database Fields

    -

    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.

    -

    Int Fields can be AutoIncrementing, and you can optionally -specify one field to be Primary Key (it must be of type Int or String).

    -

    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.

    -

    FileDb Records

    -

    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:

    -
    - - - - - -
    - FileDb employeesDb = new FileDb();
    - employeesDb.Open( Employees.fdb" );
    -
    - Table employees = employeesDb.SelectAllRecords();
    - Record record = - employees[0];
    - int id = (int) record["EmployeeId"];
    - // or
    - id - = (int) record[0];
    -
    -
    -

    To use a Table with LINQ, you do this:

    -
    - - - - - -
    - var recs = from e in - employees
    -           where (string) - e["FirstName"] == "John"
    -           select e;
    -
    -
    -

    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.

    -

    Records and Custom Objects

    -

    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.

    -
    - - - - - -
    - public class Employee
    - {
    -    public int EmployeeID { get; set; }
    -    public string LastName { get; set; }
    -     - public string - FirstName { get; set; }
    -     - public string Title { - get; set; }
    -     - public string - TitleOfCourtesy { get; set; }
    -     - public DateTime - BirthDate { get; set; }
    -     - public DateTime - HireDate { get; set; }
    -     - public string Address - { get; set; }
    -     - public string City { - get; set; }
    -     - public string Region { - get; set; }
    -     - public string - PostalCode { get; set; }
    -     - public string Country - { get; set; }
    -     - public string - HomePhone { get; set; }
    -     - public string - Extension { get; set; }
    -     - public Byte[] Photo { - get; set; }
    -     - public string Notes { - get; set; }
    -     - public int ReportsTo { - get; set; }
    - }
    -
    -
    -

    The templated SelectRecords versions return a IList<T> - where T is your custom type.

    -
    - - - - - -
    - - IList<Employee> - employees = employeesDb.SelectAllRecords<Employee>();
    - Employee employee - = employees[0];
    - int id = Employee.EmployeeId;
    -
    - var emps = from e in - employees
    -           where e.FirstName - == "John"
    -           select e;
    -
    -
    -

    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.

    -

    Searching and Filtering

    -

    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).

    -

    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 - String.Contains. See the section on - Regular Expressions below for more info. Field names - prefixed with ~ specifies no-case comparison (for - strings only).

    -

    Each time you use () around an expression, a new -FilterExpressionGroup will be created. The inner-most expressions are evaluated -first, just as in SQL.

    - -

    Example 1: Create a FilterExpression

    -
    -
    - - - - - -
    - // build an expression manually
    - FilterExpression searchExp = new FilterExpression( "LastName", "Peacock", - Equality.Equal );
    -
    - // build the same expression using the - parser
    - searchExp = FilterExpression.Parse( "LastName = 'Peacock'" );
    - Table table = employeesDb.SelectRecords( - searchExp, - new string[] { "ID", "LastName" } );
    -
    - // Or you can simply pass the string filter - directly - a FilterExpression will be - created in the same way as above
    -
    - table = employeesDb.SelectRecords( "LastName - = 'Peacock'", new string[] { "ID", "LastName" - } );
    -
    - foreach( Record record in table )
    - {
    -    foreach( object value in record )
    -    {
    -         - Debug.WriteLine( value );
    -     - }
    - }
    -
    -
    - -


    -Example 2: Create a FilterExpressionGroup

    -
    -

    This example creates two identical FilterExpressionGroups, -one using the Expression Parser and the other with code.

    -
    - - - - - -
    // For string fields there are - 2 ways to specify no-case - comparisons: you can prefix fieldnames with ~ or you can use ~= as - demonstrated below
    - // The first form is needed when using the IN operator, eg.
    - FilterExpressionGroup filterExpGrp = - FilterExpressionGroup.Parse( "(FirstName ~= 'andrew' OR ~FirstName = 'nancy') - AND LastName = 'Fuller'" );
    - Table table = employeesDb.SelectRecords( filterExpGrp );
    -
    - // equivalent building it manually
    - var fname1Exp = new FilterExpression( "FirstName", "andrew", Equality.Equal, - MatchType.IgnoreCase );
    - var fname2Exp = new FilterExpression( "FirstName", "nancy", Equality.Equal, - MatchType.IgnoreCase );
    - var lnameExp = new FilterExpression( "LastName", "Fuller", Equality.Equal ); - // this constructor defaults to MatchType.UseCase
    - var fnamesGrp = new FilterExpressionGroup();
    - fnamesGrp.Add( BoolOp.Or, fname1Exp );
    - fnamesGrp.Add( BoolOp.Or, fname2Exp );
    - var allNamesGrp = new FilterExpressionGroup();
    - allNamesGrp.Add( BoolOp.And, lnameExp );
    - allNamesGrp.Add( BoolOp.And, fnamesGrp );
    -
    - table = employeesDb.SelectRecords( allNamesGrp );
    -
    - // or just pass the filter string directly
    -
    - table = employeesDb.SelectRecords( "(FirstName ~= 'andrew' OR ~FirstName = 'nancy') - AND LastName = 'Fuller'" );
    -  
    -
    -
    -


    -FileDb supports these comparison operators:

    - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    = Equality
    ~= No-case equality - strings only
    <> Not Equal
    != Not Equal (same as <>)
    >= Greater than or Equal
    <= Less than or Equal
    REGEX Use Regular Expression
    CONTAINS Use the .NET String's Contains method
    IN Creates a HashSet of values to use like SQL - IN operator
    NOT Logical Negation, e.g NOT CONTAINS
    -
    - - -
    - -

     

    -
    -

    REGEX - -Regular Expressions in searches and filtering

    -

    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.

    - -
    - - - - - -
    // Using the Expression Parser
    -
    - // You can use brackets around fieldnames if there are spaces in the - name
    - FilterExpressionGroup filterExpGrp = FilterExpressionGroup.Parse( "(~FirstName = 'steven' OR [FirstName] - REGEX 'NANCY') AND LastName = 'Fuller'" );
    - Table table = employeesDb.SelectRecords( filterExpGrp );
    -
    - // we can manually build the same FilterExpressionGroup
    - var fname1Exp = FilterExpression.Parse( "~FirstName = steven" );
    - var fname2Exp = new FilterExpression( "FirstName", "NANCY", Equality.Regex );
    - var lnameExp = new FilterExpression( "LastName", "Fuller", Equality.Equal );
    - var fnamesGrp = new FilterExpressionGroup();
    - fnamesGrp.Add( BoolOp.Or, fname1Exp );
    - fnamesGrp.Add( BoolOp.Or, fname2Exp );
    - var allNamesGrp = new FilterExpressionGroup();
    - allNamesGrp.Add( BoolOp.And, lnameExp );
    - allNamesGrp.Add( BoolOp.And, fnamesGrp );
    -
    - table = employeesDb.SelectRecords( allNamesGrp );
    -
    -
    -
    - -

     

    -
    -

    Using CONTAINS in searches and filtering

    -

    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.

    - -
    - - - - - -
    // You can use brackets around fieldnames if there are spaces in the - name
    - FilterExpressionGroup filterExpGrp = FilterExpressionGroup.Parse( "(~FirstName = 'steven' OR [FirstName] - CONTAINS 'NANC') AND LastName = 'Fuller'" );
    - Table table = employeesDb.SelectRecords( filterExpGrp );
    -
    - // we can manually build the same FilterExpressionGroup
    - var fname1Exp = FilterExpression.Parse( "~FirstName = steven" );
    - var fname2Exp = new FilterExpression( "FirstName", "NANCY", Equality.Contains );
    - var lnameExp = new FilterExpression( "LastName", "Fuller", Equality.Equal );
    - var fnamesGrp = new FilterExpressionGroup();
    - fnamesGrp.Add( BoolOp.Or, fname1Exp );
    - fnamesGrp.Add( BoolOp.Or, fname2Exp );
    - var allNamesGrp = new FilterExpressionGroup();
    - allNamesGrp.Add( BoolOp.And, lnameExp );
    - allNamesGrp.Add( BoolOp.And, fnamesGrp );
    -
    - table = employeesDb.SelectRecords( allNamesGrp );
    -
    -
    -
    -

     

    -

    Sort Ordering

    -

    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 ~.

    -

    Example:

    -
    - - - - - -
    - - Table table = employeesDb.SelectAllRecords( new string[] { "ID", "Firstname", "LastName", - "Age" }, false, new string[] { "~LastName", "~FirstName", "!Age" } );
    -
    -
    -

    Selecting a Table from a Table

    -

    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.

    -

    Example:

    -
    - - - - - -
    - - customersDb.Open( path + "Customers.fdb" );
    -
    -// select all fields and records from the database table
    -Table customers = customersDb.SelectAllRecords();
    -
    -Table subCusts = customers.SelectRecords( "CustomerID <> 'ALFKI'",
    -new string[] { "CustomerID", "CompanyName", "City" }, new string[] { "~City", "~CompanyName" -} );
    -
    -
    -

    Encryption

    -

    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.

    -

    Persisting Tables

    -

    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.

    -
    - - - - - -
    Table table = employeesDb.SelectAllRecords( new string[] { "ID", "Firstname", "LastName" - } );
    - table.SaveToDb( "Names.fdb" );
    -
    -
    -

    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.

    -

    Using LINQ to Objects with FileDb

    -

    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.

    -

    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.

    -

    Here is an example of doing a simple select using - LINQ:

    -
    - - - - - -
    // - Using the IN operator.  Notice the ~ - prefix on the LastName field. This is how -
    - // you can specify case insensitive searches
    -
    - Table - employees = employeesDb.SelectRecords( "~LastName - IN ('Fuller', 'Peacock')" );
    -
    - var query = - from record in employees
    - select new
    - {
    -    ID = record["EmployeeId"],
    -    Name = record["FirstName"] + " " + record["LastName"],
    -    Title = record["Title"]
    - };
    -
    - foreach( var rec in query )
    - {
    -    Debug.WriteLine( rec.ToString() );
    - }
    -
    -

    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:

    - - - - - -
    IList<Employee> employees - = employeesDb.SelectRecords<Employee>( - "~LastName - IN ('Fuller', 'Peacock')" );
    -
    - var query =
    - from e in employees
    - select e;
    -
    - foreach( var emp in query )
    - {
    -    Debug.WriteLine( emp.ToString() );
    - }
    -
    -
    -

    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 -FilterExpression.CreateInExpressionFromTable -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.

    -
    - - - - - -
    FileDb customersDb = new FileDb(),
    - ordersDb = new FileDb(),
    - orderDetailsDb = new FileDb(),
    - productsDb = new FileDb();
    -
    - customersDb.Open( "Customers.fdb" );
    - ordersDb.Open( "Orders.fdb" );
    - orderDetailsDb.Open( "OrderDetails.fdb" );
    - productsDb.Open( "Products.fdb" );
    -
    - // get our target Customer records
    - // Note that we should select only fields we - need from each table, but to keep the code
    - // simple for this example we just pass in null for the field - list
    -
    - FilterExpression filterExp = - FilterExpression.Parse( "CustomerID IN( 'ALFKI', - 'BONAP' )" );
    - FileDbNs.Table customers = - customersDb.SelectRecords( filterExp );
    -
    - // now get only Order records for the target - Customer records
    - // CreateInExpressionFromTable will create - an IN FilterExpression, which uses a HashSet -
    - // for high efficiency when filtering - records

    - filterExp = - FilterExpression.CreateInExpressionFromTable( - "CustomerID", customers, "CustomerID" );
    - FileDbNs.Table orders = - ordersDb.SelectRecords( filterExp );
    -
    - // now get only OrderDetails records for the - target Order records
    -
    - filterExp = - FilterExpression.CreateInExpressionFromTable( - "OrderID", orders, "OrderID" );
    - FileDbNs.Table orderDetails = - orderDetailsDb.SelectRecords( filterExp );
    -
    - // now get only Product records for the - target OrderDetails records
    -
    - filterExp = - FilterExpression.CreateInExpressionFromTable( - "ProductID", orderDetails, "ProductID" );
    - FileDbNs.Table products = - productsDb.SelectRecords( filterExp );
    -
    - // now we're ready to do the join
    -
    - var query =
    -    from custRec in customers
    -    join orderRec in orders on custRec["CustomerID"] - equals orderRec["CustomerID"]
    -    join orderDetailRec in orderDetails on - orderRec["OrderID"] equals - orderDetailRec["OrderID"]
    -    join productRec in products on - orderDetailRec["ProductID"] equals - productRec["ProductID"]
    -    select new
    -    {
    -        ID = custRec["CustomerID"],
    -        CompanyName = custRec["CompanyName"],
    -        OrderID = orderRec["OrderID"],
    -        OrderDate = orderRec["OrderDate"],
    -        ProductName = productRec["ProductName"],
    -        UnitPrice = orderDetailRec["UnitPrice"],
    -        Quantity = orderDetailRec["Quantity"]
    -    };
    -
    - foreach( var rec in query )
    - {
    -    Debug.WriteLine( rec.ToString() );
    - }
    -
    -

    Here's the same thing again using custom objects:

    - - - - - -
    // get our target Customer records
    -
    - FilterExpression filterExp = - FilterExpression.Parse( "CustomerID IN( 'ALFKI', - 'BONAP' )" );
    - IList<Customer> customers = - customersDb.SelectRecords<Customer>( filterExp );

    - filterExp = - FilterExpression.CreateInExpressionFromTable<Customer>( - "CustomerID", customers, "CustomerID" );
    - IList<Order> orders = - ordersDb.SelectRecords<Order>( filterExp );
    -
    - // now get only OrderDetails records for the - target Order records
    -
    - filterExp = - FilterExpression.CreateInExpressionFromTable<Order>( - "OrderID", orders, "OrderID" );
    - IList<OrderDetail> orderDetails = - orderDetailsDb.SelectRecords<OrderDetail>( filterExp );
    -
    - // now get only Product records for the - target OrderDetails records
    -
    - filterExp = - FilterExpression.CreateInExpressionFromTable<OrderDetail>( - "ProductID", orderDetails, "ProductID" );
    - IList<Product> products = - productsDb.SelectRecords<Product>(( filterExp );
    -
    - // now we're ready to do the join
    -
    - var query =
    -    from custRec in customers
    -    join orderRec in orders on custRec.CustomerID - equals orderRec.CustomerID
    -    join orderDetailRec in orderDetails on - orderRec.OrderID equals orderDetailRec.OrderID
    -    join productRec in products on - orderDetailRec.ProductID equals productRec.ProductID
    -    select new
    -    {
    -        ID = custRec.CustomerID,
    -        CompanyName = custRec.CompanyName,
    -        OrderID = orderRec.OrderID,
    -        OrderDate = orderRec.OrderDate,
    -        ProductName = productRec.ProductName,
    -        UnitPrice = orderDetailRec.UnitPrice,
    -        Quantity = orderDetailRec.Quantity
    -    };
    -
    - foreach( var rec in query )
    - {
    -    Debug.WriteLine( rec.ToString() );
    - }
    -
    -

     

    -
    -

    - Creating a Database

    - -

    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.

    - -
    - - - - -
    Field field;
    - var fieldLst = new List<Field>( 20 );
    - field = new Field( "ID", DataType.Int );
    - field.AutoIncStart = 0;
    - field.IsPrimaryKey = true;
    - fields.Add( field );
    - field = new Field( "FirstName", DataType.String );
    - fields.Add( field );
    - field = new Field( "LastName", DataType.String );
    - fields.Add( field );
    - field = new Field( "BirthDate", DataType.DateTime );
    - fields.Add( field );
    - field = new Field( "IsCitizen", DataType.Bool );
    - fields.Add( field );
    - field = new Field( "DoubleField", DataType.Double );
    - fields.Add( field );
    - field = new Field( "ByteField", DataType.Byte );
    - fields.Add( field );
    -
    - // array types
    - field = new Field( "StringArrayField", DataType.String );
    - field.IsArray = true;
    - fields.Add( field );
    - field = new Field( "ByteArrayField", DataType.Byte );
    - field.IsArray = true;
    - fields.Add( field );
    - field = new Field( "IntArrayField", DataType.Int );
    - field.IsArray = true;
    - fields.Add( field );
    - field = new Field( "DoubleArrayField", DataType.Double );
    - field.IsArray = true;
    - fields.Add( field );
    - field = new Field( "DateTimeArrayField", DataType.DateTime );
    - field.IsArray = true;
    - fields.Add( field );
    - field = new Field( "BoolArray", DataType.Bool );
    - field.IsArray = true;
    - fields.Add( field );

    -
    - var myDb = new FileDb();

    - myDb.Create( "MyDatabase.fdb", fieldLst.ToArray() );
    -
    -
    -


    -Adding Records

    -

    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).

    - -
    - - - - -
    -var record = new FieldValues();
    - record.Add( "FirstName", "Nancy" );
    - record.Add( "LastName", "Davolio" );
    - record.Add( "BirthDate", new DateTime( 1968, 12, 8 ) );
    - record.Add( "IsCitizen", true );
    - record.Add( "Double", 1.23 );
    - record.Add( "Byte", 1 );
    - record.Add( "StringArray", new string[] { "s1", "s2", "s3" } );
    - record.Add( "ByteArray", new Byte[] { 1, 2, 3, 4 } );
    - record.Add( "IntArray", new int[] { 100, 200, 300, 400 } );
    - record.Add( "DoubleArray", new double[] { 1.2, 2.4, 3.6, 4.8 } );
    - record.Add( "DateTimeArray", new DateTime[] { DateTime.Now, DateTime.Now, - DateTime.Now, DateTime.Now } );
    - record.Add( "BoolArray", new bool[] { true, false, true, false } );
    -
    - myDb.AddRecord( record );
    -
    -

     

    -
    - - - - \ No newline at end of file diff --git a/FileDbCache/UWP/FileDbCache.UWP.csproj b/FileDbCache/UWP/FileDbCache.UWP.csproj index 425fa2fe..e80fd41a 100644 --- a/FileDbCache/UWP/FileDbCache.UWP.csproj +++ b/FileDbCache/UWP/FileDbCache.UWP.csproj @@ -45,6 +45,9 @@ + + 7.4.3 + 6.2.8 @@ -60,12 +63,6 @@ MapControl.UWP - - - False - ..\FileDb\FileDbPcl.dll - - 14.0 diff --git a/FileDbCache/UWP/FileDbCache.cs b/FileDbCache/UWP/FileDbCache.cs index 66ae0999..dcd73c06 100644 --- a/FileDbCache/UWP/FileDbCache.cs +++ b/FileDbCache/UWP/FileDbCache.cs @@ -25,8 +25,7 @@ namespace MapControl.Caching private const string expiresField = "Expires"; private readonly FileDb fileDb = new FileDb(); - private readonly StorageFolder folder; - private readonly string fileName; + private readonly string dbPath; public FileDbCache(StorageFolder folder, string fileName = "TileCache.fdb", bool autoFlush = true, int autoCleanThreshold = -1) { @@ -40,16 +39,15 @@ namespace MapControl.Caching throw new ArgumentNullException("The parameter fileName must not be null."); } - this.folder = folder; - this.fileName = fileName; + dbPath = Path.Combine(folder.Path, "TileCache.fdb"); fileDb.AutoFlush = autoFlush; fileDb.AutoCleanThreshold = autoCleanThreshold; - Application.Current.Resuming += async (s, e) => await Open(); + Application.Current.Resuming += (s, e) => Open(); Application.Current.Suspending += (s, e) => Close(); - var task = Open(); + Open(); } public void Dispose() @@ -78,12 +76,7 @@ namespace MapControl.Caching throw new ArgumentNullException("The parameter key must not be null."); } - if (!fileDb.IsOpen) - { - return null; - } - - return Task.Run(() => Get(key)); + return fileDb.IsOpen ? Task.Run(() => Get(key)) : null; } public Task SetAsync(string key, IBuffer buffer, DateTime expiration) @@ -98,14 +91,14 @@ namespace MapControl.Caching throw new ArgumentNullException("The parameter buffer must not be null."); } - return Task.Run(async () => + return Task.Run(() => { if (fileDb.IsOpen) { var bytes = buffer.ToArray(); var ok = AddOrUpdateRecord(key, bytes, expiration); - if (!ok && (await RepairDatabase())) + if (!ok && RepairDatabase()) { AddOrUpdateRecord(key, bytes, expiration); } @@ -113,23 +106,20 @@ namespace MapControl.Caching }); } - private async Task Open() + private void Open() { if (!fileDb.IsOpen) { try { - var file = await folder.GetFileAsync(fileName); - var stream = await file.OpenAsync(FileAccessMode.ReadWrite); - - fileDb.Open(stream.AsStream()); - Debug.WriteLine("FileDbCache: Opened database with {0} cached items in {1}", fileDb.NumRecords, file.Path); + fileDb.Open(dbPath); + Debug.WriteLine("FileDbCache: Opened database with {0} cached items in {1}", fileDb.NumRecords, dbPath); Clean(); } catch { - await CreateDatabase(); + CreateDatabase(); } } } @@ -142,24 +132,21 @@ namespace MapControl.Caching } } - private async Task CreateDatabase() + private void CreateDatabase() { Close(); - var file = await folder.CreateFileAsync(fileName, CreationCollisionOption.ReplaceExisting); - var stream = await file.OpenAsync(FileAccessMode.ReadWrite); - - fileDb.Create(stream.AsStream(), new Field[] + fileDb.Create(dbPath, new Field[] { new Field(keyField, DataTypeEnum.String) { IsPrimaryKey = true }, new Field(valueField, DataTypeEnum.Byte) { IsArray = true }, new Field(expiresField, DataTypeEnum.DateTime) }); - Debug.WriteLine("FileDbCache: Created database " + file.Path); + Debug.WriteLine("FileDbCache: Created database " + dbPath); } - private async Task RepairDatabase() + private bool RepairDatabase() { try { @@ -173,12 +160,12 @@ namespace MapControl.Caching try { - await CreateDatabase(); + CreateDatabase(); return true; } catch (Exception ex) { - Debug.WriteLine("FileDbCache: Creating database {0}: {1}", Path.Combine(folder.Path, fileName), ex.Message); + Debug.WriteLine("FileDbCache: Creating database {0}: {1}", dbPath, ex.Message); } return false; diff --git a/FileDbCache/WPF/FileDbCache.WPF.csproj b/FileDbCache/WPF/FileDbCache.WPF.csproj index 46266aef..b722e9de 100644 --- a/FileDbCache/WPF/FileDbCache.WPF.csproj +++ b/FileDbCache/WPF/FileDbCache.WPF.csproj @@ -37,8 +37,8 @@ ..\..\MapControl.snk - - ..\FileDb\FileDb.dll + + ..\..\packages\FileDb.Net.7.4.3\lib\net45\FileDb.Net.dll @@ -51,6 +51,7 @@ MapControl.snk +