📄 database.cs
字号:
#if !USE_GENERICS
namespace Perst
{
using System;
using System.Collections;
using Perst.Impl;
/// <summary>
/// This class emulates relational database on top of Perst storage
/// It maintain class extends, associated indices, prepare queries.
/// </summary>
public class Database
{
/// <summary>
/// Constructor of database. This method initialize database if it not initialized yet.
/// </summary>
/// <param name="storage">opened storage. Storage should be either empty (non-initialized, either
/// previously initialized by the this method. It is not possible to open storage with
/// root object other than table index created by this constructor.
/// </param>
/// <param name="multithreaded"><code>true</code> if database should support concurrent access
/// to the data from multiple threads</param>
public Database(Storage storage, bool multithreaded)
{
this.storage = storage;
this.multithreaded = multithreaded;
metadata = (Index)storage.Root;
if (metadata == null)
{
metadata = storage.CreateIndex(typeof(string), true);
storage.Root = metadata;
}
tables = new Hashtable();
IDictionaryEnumerator e = metadata.GetDictionaryEnumerator();
while (e.MoveNext())
{
Type table = ClassDescriptor.lookup(storage, (string)e.Key);
tables[table] = (Table)e.Value;
}
}
/// <summary>
/// Constructor of single threaded database. This method initialize database if it not initialized yet.
/// </summary>
/// <param name="storage">opened storage. Storage should be either empty (non-initialized, either
/// previously initialized by the this method. It is not possible to open storage with
/// root object other than table index created by this constructor.
/// </param>
public Database(Storage storage)
: this(storage, false)
{
}
/// <summary>
/// Create table for the specified class.
/// This function does nothing if table for such class already exists
/// </summary>
/// <param name="table">class corresponding to the table
/// </param>
/// <returns> <code>true</code> if table is created, <code>false</code> if table
/// alreay exists
/// </returns>
public bool CreateTable(Type table)
{
if (multithreaded)
{
metadata.ExclusiveLock();
}
if (!tables.ContainsKey(table))
{
Table t = new Table();
t.extent = storage.CreateSet();
t.indices = storage.CreateLink();
t.indicesMap = new Hashtable();
tables[table] = t;
metadata[table.FullName] = t;
return true;
}
return false;
}
/// <summary>
/// Drop table associated with this class. Do nothing if there is no such table in the database.
/// </summary>
/// <param name="table">class corresponding to the table
/// </param>
/// <returns> <code>true</code> if table is deleted, <code>false</code> if table
/// is not found
/// </returns>
public bool DropTable(Type table)
{
if (multithreaded)
{
metadata.ExclusiveLock();
}
if (tables.ContainsKey(table))
{
tables.Remove(table);
metadata.Remove(table.FullName);
return true;
}
return false;
}
/// <summary>
/// Add new record to the table. Record is inserted in table corresponding to the class of the object.
/// Record will be automatically added to all indices existed for this table.
/// If there is not table associated with class of this object, then
/// database will search for table associated with superclass and so on...
/// </summary>
/// <param name="record">object to be inserted in the table</param>
/// <returns> <code>true</code> if record was successfully added to the table, <code>false</code>
/// if there is already such record (object with the same ID) in the table
/// </returns>
/// <exception cref="StorageError"> StorageError(CLASS_NOT_FOUND) exception is thrown if there is no table corresponding to
/// record class
/// </exception>
public bool AddRecord(IPersistent record)
{
return AddRecord(record.GetType(), record);
}
private Table locateTable(Type cls, bool exclusive)
{
Table table = null;
if (multithreaded)
{
metadata.SharedLock();
}
for (Type c = cls; c != null && (table = (Table)tables[c]) == null; c = c.BaseType);
if (table == null)
{
throw new StorageError(StorageError.ErrorCode.CLASS_NOT_FOUND, cls.FullName);
}
if (exclusive)
{
table.extent.ExclusiveLock();
}
else
{
table.extent.SharedLock();
}
return table;
}
/// <summary>
/// Add new record to the specified table. Record is inserted in table corresponding to the specified class.
/// Record will be automatically added to all indices existed for this table.
/// </summary>
/// <param name="table">class corresponding to the table
/// </param>
/// <param name="record">object to be inserted in the table
/// </param>
/// <returns> <code>true</code> if record was successfully added to the table, <code>false</code>
/// if there is already such record (object with the same ID) in the table
/// </returns>
/// <exception cref="StorageError">StorageError(CLASS_NOT_FOUND) exception is thrown if there is no table corresponding to
/// record class
/// </exception>
public bool AddRecord(Type table, IPersistent record)
{
bool added = false;
bool found = false;
if (multithreaded)
{
metadata.SharedLock();
}
for (Type c = table; c != null; c = c.BaseType)
{
Table t = (Table)tables[c];
if (t != null)
{
found = true;
if (multithreaded)
{
t.extent.ExclusiveLock();
}
if (!t.extent.Contains(record))
{
t.extent.Add(record);
foreach (FieldIndex index in t.indicesMap.Values)
{
index.Put(record);
}
added = true;
}
}
}
if (!found)
{
throw new StorageError(StorageError.ErrorCode.CLASS_NOT_FOUND, table.FullName);
}
return added;
}
/// <summary>
/// Delete record from the table. Record is removed from the table corresponding to the class
/// of the object. Record will be automatically added to all indices existed for this table.
/// If there is not table associated with class of this object, then
/// database will search for table associated with superclass and so on...
/// Object represented the record will be also deleted from the storage.
/// </summary>
/// <param name="record">object to be deleted from the table
/// </param>
/// <returns> <code>true</code> if record was successfully deleted from the table, <code>false</code>
/// if there is not such record (object with the same ID) in the table
/// </returns>
/// <exception cref="StorageError">StorageError(CLASS_NOT_FOUND) exception is thrown if there is no table corresponding to
/// record class
/// </exception>
public bool DeleteRecord(IPersistent record)
{
return DeleteRecord(record.GetType(), record);
}
/// <summary>
/// Delete record from the specified table. Record is removed from the table corresponding to the
/// specified class. Record will be automatically added to all indices existed for this table.
/// Object represented the record will be also deleted from the storage.
/// </summary>
/// <param name="table">class corresponding to the table
/// </param>
/// <param name="record">object to be deleted from the table
/// </param>
/// <returns> <code>true</code> if record was successfully deleted from the table, <code>false</code>
/// if there is not such record (object with the same ID) in the table
/// </returns>
/// <exception cref="StorageError">StorageError(CLASS_NOT_FOUND) exception is thrown if there is no table corresponding to
/// specified class
/// </exception>
public bool DeleteRecord(Type table, IPersistent record)
{
bool removed = false;
bool found = false;
if (multithreaded)
{
metadata.SharedLock();
}
for (Type c = table; c != null; c = c.BaseType)
{
Table t = (Table)tables[c];
if (t != null)
{
found = true;
if (t.extent.Contains(record))
{
if (multithreaded)
{
t.extent.ExclusiveLock();
}
t.extent.Remove(record);
foreach (FieldIndex index in t.indicesMap.Values)
{
index.Remove(record);
}
removed = true;
}
}
}
if (!found)
{
throw new StorageError(StorageError.ErrorCode.CLASS_NOT_FOUND, table.FullName);
}
if (removed)
{
record.Deallocate();
}
return removed;
}
/// <summary>
/// Add new index to the table. If such index already exists this method does nothing.
/// </summary>
/// <param name="table">class corresponding to the table
/// </param>
/// <param name="key">field of the class to be indexed
/// </param>
/// <param name="unique">if index is unique or not
/// </param>
/// <exception cref="StorageError">StorageError(CLASS_NOT_FOUND) exception is thrown if there is no table corresponding to
/// the specified class
/// </exception>
/// <returns> <code>true</code> if index is created, <code>false</code> if index
/// already exists
/// </returns>
public bool CreateIndex(Type table, string key, bool unique)
{
Table t = locateTable(table, true);
if (!t.indicesMap.ContainsKey(key))
{
FieldIndex index = storage.CreateFieldIndex(table, key, unique);
t.indicesMap[key] = index;
t.indices.Add(index);
return true;
}
return false;
}
/// <summary>
/// Drop index for the specified table and key.
/// Does nothing if there is no such index.
/// </summary>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -