Initial Commit
commit
a4108ac920
|
@ -0,0 +1,41 @@
|
|||
# Autosave files
|
||||
*~
|
||||
|
||||
# build
|
||||
[Oo]bj/
|
||||
[Bb]in/
|
||||
packages/
|
||||
TestResults/
|
||||
|
||||
# globs
|
||||
Makefile.in
|
||||
*.DS_Store
|
||||
*.sln.cache
|
||||
*.suo
|
||||
*.cache
|
||||
*.pidb
|
||||
*.userprefs
|
||||
*.usertasks
|
||||
config.log
|
||||
config.make
|
||||
config.status
|
||||
aclocal.m4
|
||||
install-sh
|
||||
autom4te.cache/
|
||||
*.user
|
||||
*.tar.gz
|
||||
tarballs/
|
||||
test-results/
|
||||
Thumbs.db
|
||||
.vs/
|
||||
|
||||
# Mac bundle stuff
|
||||
*.dmg
|
||||
*.app
|
||||
|
||||
# resharper
|
||||
*_Resharper.*
|
||||
*.Resharper
|
||||
|
||||
# dotCover
|
||||
*.dotCover
|
|
@ -0,0 +1,186 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using oodb.descriptor;
|
||||
using oodb.mapping;
|
||||
using oodb.persistence;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using System.CodeDom;
|
||||
using System.ComponentModel;
|
||||
using System.Reflection;
|
||||
using oodb.mapping.collections;
|
||||
namespace oodb
|
||||
{
|
||||
public class OODB
|
||||
{
|
||||
|
||||
public PersistenceCache PersistenceCache { get; }
|
||||
public StorageAdapter StorageAdapter { get; }
|
||||
|
||||
internal Dictionary<Type, Descriptor> descriptors = new Dictionary<Type, Descriptor>();
|
||||
internal Dictionary<Type, FlatTypeMapping> flatTypeMappings = new Dictionary<Type, FlatTypeMapping>();
|
||||
|
||||
|
||||
public OODB(String storagePath)
|
||||
:this(new DirectoryInfo(storagePath))
|
||||
{
|
||||
}
|
||||
|
||||
public OODB(DirectoryInfo storageDirectory)
|
||||
{
|
||||
PersistenceCache = new PersistenceCache(this);
|
||||
StorageAdapter = new StorageAdapter(this,storageDirectory);
|
||||
|
||||
PopulateFlatMappings();
|
||||
|
||||
AppDomain.CurrentDomain.ProcessExit += (sender, e) => this.Close();
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
StorageAdapter.Close();
|
||||
}
|
||||
|
||||
public void Prepare()
|
||||
{
|
||||
foreach (Descriptor descriptor in descriptors.Values)
|
||||
{
|
||||
descriptor.Initialize();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public OODB Add<T>() where T : Persistent => Add(typeof(T));
|
||||
public OODB Add(Type type)
|
||||
{
|
||||
GetDescriptor(type);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void Save(IEnumerable<Persistent> persistents)
|
||||
{
|
||||
foreach (Persistent persistent in persistents)
|
||||
Save(persistent);
|
||||
}
|
||||
public void Save(Persistent o)
|
||||
{
|
||||
PersistenceCache.Touch(o);
|
||||
StorageAdapter.Save(o);
|
||||
}
|
||||
|
||||
public void Ensure(Persistent o)
|
||||
{
|
||||
if (!StorageAdapter.Knows(o.GetType(), o.PersistenceID))
|
||||
Save(o);
|
||||
}
|
||||
|
||||
public T Load<T>(Guid persistenceID) where T: Persistent
|
||||
{
|
||||
return (T)Load(typeof(T), persistenceID);
|
||||
}
|
||||
public Persistent Load(Type type,Guid persistenceID)
|
||||
{
|
||||
if (persistenceID.Equals(Guid.Empty))
|
||||
return null;
|
||||
|
||||
try {
|
||||
return PersistenceCache.Get(type, persistenceID);
|
||||
} catch (KeyNotFoundException)
|
||||
{
|
||||
Type realType = StorageAdapter.GetDiscriminator(type, persistenceID);
|
||||
Persistent persistent = Activator.CreateInstance(type,true) as Persistent;
|
||||
|
||||
persistent.PersistenceID = persistenceID;
|
||||
PersistenceCache.Touch(persistent);
|
||||
|
||||
GetDescriptor(realType).Attach(persistent);
|
||||
|
||||
StorageAdapter.Restore(persistent);
|
||||
|
||||
return persistent;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<T> List<T>() where T:Persistent => List(typeof(T)).Select((x) => (T)x);
|
||||
public IEnumerable<Persistent> List(Type type)
|
||||
{
|
||||
return ListIdentities(type).Select((x) => Load(x.Value, x.Key));
|
||||
}
|
||||
|
||||
private IEnumerable<KeyValuePair<Guid,Type>> ListIdentities(Type type)
|
||||
{
|
||||
return StorageAdapter.List(GetDescriptor(type));
|
||||
}
|
||||
|
||||
|
||||
|
||||
public Type LookupType(string fullName)
|
||||
{
|
||||
foreach (Type t in descriptors.Keys)
|
||||
if (t.FullName.Equals(fullName))
|
||||
return t;
|
||||
throw new KeyNotFoundException(fullName);
|
||||
}
|
||||
|
||||
public Descriptor GetDescriptor(Type type)
|
||||
{
|
||||
if (!descriptors.ContainsKey(type))
|
||||
{
|
||||
descriptors[type] = new Descriptor(this, type);
|
||||
}
|
||||
return descriptors[type];
|
||||
}
|
||||
public Descriptor GetDescriptor<T>() => GetDescriptor(typeof(T));
|
||||
|
||||
public FlatTypeMapping GetFlatTypeMapping(Type type)
|
||||
{
|
||||
if (!flatTypeMappings.ContainsKey(type))
|
||||
{
|
||||
if (type.IsArray)
|
||||
{
|
||||
flatTypeMappings[type] = new ArrayMapping(this, type);
|
||||
}
|
||||
else if (type.IsSubclassOf(typeof(Persistent)))
|
||||
{
|
||||
Add(type);
|
||||
}
|
||||
else if (type.IsGenericType && ((type.GetGenericTypeDefinition() == typeof(List<>)) || (type.GetGenericTypeDefinition() == typeof(IList<>))))
|
||||
{
|
||||
FlatTypeMapping elementMapping = GetFlatTypeMapping(type.GetGenericArguments()[0]);
|
||||
flatTypeMappings[type] = new ListMapping(this, type);
|
||||
} else {
|
||||
throw new KeyNotFoundException();
|
||||
}
|
||||
}
|
||||
return flatTypeMappings[type];
|
||||
}
|
||||
|
||||
public ExtendedFieldHandling CreateExtendedFieldHandling(FieldInfo fieldInfo)
|
||||
{
|
||||
if (fieldInfo.FieldType.IsGenericType){
|
||||
Type genericTypeDefinition = fieldInfo.FieldType.GetGenericTypeDefinition();
|
||||
|
||||
if (genericTypeDefinition == typeof(ISet<>))
|
||||
{
|
||||
return new ISetExtendedHandling(this, fieldInfo);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
|
||||
private void PopulateFlatMappings()
|
||||
{
|
||||
flatTypeMappings[typeof(string)] = new StringMapping(this);
|
||||
flatTypeMappings[typeof(int)] = new IntegerMapping(this);
|
||||
flatTypeMappings[typeof(short)] = new IntegerMapping(this);
|
||||
flatTypeMappings[typeof(byte)] = new IntegerMapping(this);
|
||||
flatTypeMappings[typeof(float)] = new DoubleMapping(this);
|
||||
flatTypeMappings[typeof(double)] = new DoubleMapping(this);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
using System;
|
||||
namespace oodb
|
||||
{
|
||||
public abstract class Persistent
|
||||
{
|
||||
public Guid PersistenceID { get; internal set; }
|
||||
|
||||
public Persistent()
|
||||
{
|
||||
PersistenceID = Guid.NewGuid();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
// Information about this assembly is defined by the following attributes.
|
||||
// Change them to the values specific to your project.
|
||||
|
||||
[assembly: AssemblyTitle("sharp-oodb")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("")]
|
||||
[assembly: AssemblyCopyright("${AuthorCopyright}")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
|
||||
// The form "{Major}.{Minor}.*" will automatically update the build and revision,
|
||||
// and "{Major}.{Minor}.{Build}.*" will update just the revision.
|
||||
|
||||
[assembly: AssemblyVersion("1.0.*")]
|
||||
|
||||
// The following attributes are used to specify the signing key for the assembly,
|
||||
// if desired. See the Mono documentation for more information about signing.
|
||||
|
||||
//[assembly: AssemblyDelaySign(false)]
|
||||
//[assembly: AssemblyKeyFile("")]
|
|
@ -0,0 +1,221 @@
|
|||
using System;
|
||||
using oodb.descriptor;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.Remoting.Metadata;
|
||||
using System.Runtime.Remoting.Messaging;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Xml.Xsl.Runtime;
|
||||
using oodb.index;
|
||||
namespace oodb
|
||||
{
|
||||
public class QueryField
|
||||
{
|
||||
public string FieldName { get; }
|
||||
|
||||
public QueryField(String fieldName)
|
||||
{
|
||||
FieldName = fieldName;
|
||||
}
|
||||
|
||||
public Predicate Contains(object value)
|
||||
{
|
||||
return new Predicate.Contains(this, value);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class Predicate
|
||||
{
|
||||
public QueryField QueryField { get; }
|
||||
|
||||
public Predicate(QueryField queryField)
|
||||
{
|
||||
QueryField = queryField;
|
||||
}
|
||||
|
||||
public virtual bool MatchesTextValues => false;
|
||||
|
||||
public virtual bool TextMatch(string textValue) { throw new NotSupportedException(); }
|
||||
public abstract bool Match(object value);
|
||||
|
||||
public OrPredicate Or => new OrPredicate(this);
|
||||
|
||||
|
||||
public class OrPredicate : Predicate
|
||||
{
|
||||
public HashSet<Predicate> Predicates { get; } = new HashSet<Predicate>();
|
||||
|
||||
public OrPredicate(Predicate creator)
|
||||
:base(creator.QueryField)
|
||||
{
|
||||
Predicates.Add(creator);
|
||||
}
|
||||
|
||||
public OrPredicate Contains(object value)
|
||||
{
|
||||
Predicates.Add(new Predicate.Contains(this.QueryField, value));
|
||||
return this;
|
||||
}
|
||||
|
||||
public override bool MatchesTextValues
|
||||
{
|
||||
get {
|
||||
foreach (Predicate predicate in Predicates)
|
||||
if (!predicate.MatchesTextValues)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool TextMatch(string textValue)
|
||||
{
|
||||
foreach (Predicate predicate in Predicates)
|
||||
if (predicate.TextMatch(textValue))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool Match(object value)
|
||||
{
|
||||
foreach (Predicate predicate in Predicates)
|
||||
if (predicate.Match(value))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public class Contains : Predicate
|
||||
{
|
||||
public object Value { get; }
|
||||
|
||||
public Contains(QueryField queryField,object value)
|
||||
:base(queryField)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public override bool Match(object value)
|
||||
{
|
||||
if ((Value == null) || String.Empty.Equals(Value))
|
||||
return true;
|
||||
|
||||
if (value == null)
|
||||
return false;
|
||||
|
||||
return (value as string).Contains(Value as string);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class Query<T> where T: Persistent
|
||||
{
|
||||
public virtual AlternativesQuery<T> Or(Query<T> alternativeQuery) => new AlternativesQuery<T>(this, alternativeQuery);
|
||||
public virtual AlternativesQuery<T> Or(params Predicate[] predicates) => new AlternativesQuery<T>(this, new Query<T>(predicates));
|
||||
|
||||
public HashSet<Predicate> Predicates { get; } = new HashSet<Predicate>();
|
||||
|
||||
|
||||
protected Query()
|
||||
{
|
||||
}
|
||||
|
||||
public Query(IEnumerable<Predicate> predicates)
|
||||
{
|
||||
foreach (Predicate predicate in predicates)
|
||||
{
|
||||
Predicates.Add(predicate);
|
||||
}
|
||||
}
|
||||
|
||||
public Query(params Predicate[] predicates)
|
||||
{
|
||||
foreach (Predicate predicate in predicates)
|
||||
{
|
||||
Predicates.Add(predicate);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<Predicate> GetPredicates(QueryField queryField)
|
||||
{
|
||||
return Predicates.Where((x) => x.QueryField == queryField);
|
||||
}
|
||||
|
||||
public virtual IEnumerable<T> Search(OODB oodb)
|
||||
{
|
||||
Descriptor descriptor = oodb.GetDescriptor<T>();
|
||||
HashSet<QueryField> predicateFields = new HashSet<QueryField>();
|
||||
|
||||
foreach (Predicate predicate in Predicates)
|
||||
{
|
||||
predicateFields.Add(predicate.QueryField);
|
||||
}
|
||||
|
||||
Guid[] results = null;
|
||||
|
||||
foreach (QueryField queryField in predicateFields)
|
||||
{
|
||||
FieldInfo fieldInfo = descriptor.GetFieldInfo(queryField.FieldName);
|
||||
if (!oodb.StorageAdapter.HasSearchIndex(fieldInfo))
|
||||
throw new NotSupportedException("Queries must use indexed fields");
|
||||
|
||||
SearchIndex searchIndex = oodb.StorageAdapter.GetSearchIndex(fieldInfo);
|
||||
|
||||
foreach (Predicate predicate in GetPredicates(queryField))
|
||||
{
|
||||
IEnumerable<Guid> myresults = searchIndex.Query(predicate);
|
||||
if (results == null)
|
||||
{
|
||||
results = myresults.ToArray();
|
||||
} else {
|
||||
results = results.Intersect(myresults).ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return results.Select((id)=>oodb.Load<T>(id));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class AlternativesQuery<T> : Query<T> where T:Persistent
|
||||
{
|
||||
public HashSet<Query<T>> Alternatives = new HashSet<Query<T>>();
|
||||
|
||||
public AlternativesQuery(params Query<T>[] queries)
|
||||
{
|
||||
foreach (Query<T> alternative in queries)
|
||||
Alternatives.Add(alternative);
|
||||
}
|
||||
|
||||
public override AlternativesQuery<T> Or(Query<T> alternativeQuery)
|
||||
{
|
||||
Alternatives.Add(alternativeQuery);
|
||||
return this;
|
||||
}
|
||||
|
||||
public override AlternativesQuery<T> Or(params Predicate[] predicates)
|
||||
{
|
||||
Alternatives.Add(new Query<T>(predicates));
|
||||
return this;
|
||||
}
|
||||
|
||||
public override IEnumerable<T> Search(OODB oodb)
|
||||
{
|
||||
return Alternatives.SelectMany((alternative) => alternative.Search(oodb)).Distinct();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,271 @@
|
|||
using System;
|
||||
using oodb.descriptor;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using oodb.mapping;
|
||||
using sharp.logging;
|
||||
using System.Linq;
|
||||
using oodb.index;
|
||||
namespace oodb
|
||||
{
|
||||
public class StorageAdapter
|
||||
{
|
||||
public OODB OODB { get; }
|
||||
public DirectoryInfo BaseDirectory { get; }
|
||||
|
||||
Dictionary<Type, TypeStorage> typeStorages = new Dictionary<Type, TypeStorage>();
|
||||
|
||||
public StorageAdapter(OODB oodb,DirectoryInfo baseDirectory)
|
||||
{
|
||||
OODB = oodb;
|
||||
BaseDirectory = baseDirectory;
|
||||
|
||||
if (!BaseDirectory.Exists)
|
||||
BaseDirectory.Create();
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
foreach (KeyValuePair<Type,TypeStorage> kvp in typeStorages)
|
||||
{
|
||||
foreach (Index index in kvp.Value.indeces)
|
||||
index.Save();
|
||||
}
|
||||
}
|
||||
|
||||
public void Save(Persistent persistent)
|
||||
{
|
||||
GetTypeStorage(persistent.GetType()).Save(persistent);
|
||||
}
|
||||
|
||||
public void Restore(Persistent persistent)
|
||||
{
|
||||
GetTypeStorage(persistent.GetType()).Restore(persistent);
|
||||
}
|
||||
|
||||
public bool Knows(Type type,Guid persistenceID)
|
||||
{
|
||||
return GetTypeStorage(type).Knows(persistenceID);
|
||||
}
|
||||
|
||||
public void Reference(Persistent persistent, FieldInfo referencing)
|
||||
{
|
||||
GetTypeStorage(persistent.GetType()).Reference(persistent, referencing);
|
||||
}
|
||||
public void UnReference(Persistent persistent, FieldInfo referencing)
|
||||
{
|
||||
GetTypeStorage(persistent.GetType()).UnReference(persistent, referencing);
|
||||
}
|
||||
|
||||
public IEnumerable<KeyValuePair<Guid,Type>> List(Descriptor descriptor)
|
||||
{
|
||||
return GetTypeStorage(descriptor.NativeType).List();
|
||||
}
|
||||
|
||||
public Type GetDiscriminator(Type type,Guid persistenceID)
|
||||
{
|
||||
return GetTypeStorage(type).GetDiscriminator(persistenceID);
|
||||
}
|
||||
|
||||
|
||||
public SearchIndex GetSearchIndex(FieldInfo fieldInfo)
|
||||
{
|
||||
return GetTypeStorage(fieldInfo.DeclaringType).GetSearchIndex(fieldInfo);
|
||||
}
|
||||
public bool HasSearchIndex(FieldInfo fieldInfo)
|
||||
{
|
||||
return GetTypeStorage(fieldInfo.DeclaringType).HasSearchIndex(fieldInfo);
|
||||
}
|
||||
|
||||
|
||||
public TypeStorage GetTypeStorage(Type type)
|
||||
{
|
||||
if (!typeStorages.ContainsKey(type))
|
||||
{
|
||||
typeStorages[type] = new TypeStorage(this, type);
|
||||
}
|
||||
return typeStorages[type];
|
||||
}
|
||||
|
||||
public class TypeStorage
|
||||
{
|
||||
public StorageAdapter StorageAdapter { get; }
|
||||
|
||||
public Type PersistentType { get; }
|
||||
public DirectoryInfo Directory { get; }
|
||||
|
||||
public Descriptor Descriptor { get; }
|
||||
public TypeStorage BaseStorage { get; }
|
||||
|
||||
public HashSet<Index> indeces = new HashSet<Index>();
|
||||
public Dictionary<FieldInfo, SearchIndex> searchIndeces = new Dictionary<FieldInfo, SearchIndex>();
|
||||
|
||||
public TypeStorage(StorageAdapter storageAdapter, Type type)
|
||||
{
|
||||
StorageAdapter = storageAdapter;
|
||||
PersistentType = type;
|
||||
|
||||
Directory = new DirectoryInfo(Path.Combine(StorageAdapter.BaseDirectory.FullName, type.FullName));
|
||||
if (!Directory.Exists)
|
||||
Directory.Create();
|
||||
|
||||
Descriptor = storageAdapter.OODB.GetDescriptor(type);
|
||||
if (Descriptor.BaseDescriptor != null)
|
||||
{
|
||||
BaseStorage = StorageAdapter.GetTypeStorage(Descriptor.BaseDescriptor.NativeType);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public bool AddIndex(Index index)
|
||||
{
|
||||
return indeces.Add(index);
|
||||
}
|
||||
|
||||
public bool HasSearchIndex(FieldInfo fieldInfo) => searchIndeces.ContainsKey(fieldInfo);
|
||||
|
||||
public SearchIndex GetSearchIndex(FieldInfo fieldInfo)
|
||||
{
|
||||
if (!searchIndeces.ContainsKey(fieldInfo))
|
||||
{
|
||||
SearchIndex searchIndex = new SearchIndex(StorageAdapter.OODB, fieldInfo);
|
||||
searchIndeces.Add(fieldInfo, searchIndex);
|
||||
}
|
||||
return searchIndeces[fieldInfo];
|
||||
}
|
||||
|
||||
private void RemoveDiscriminator(Guid persistenceID)
|
||||
{
|
||||
foreach (Index index in indeces)
|
||||
{
|
||||
index.Remove(persistenceID);
|
||||
}
|
||||
|
||||
File.Delete(Path.Combine(Directory.FullName, String.Format("{0}.discriminator", persistenceID.ToString())));
|
||||
if (BaseStorage != null)
|
||||
BaseStorage.RemoveDiscriminator(persistenceID);
|
||||
}
|
||||
private String ReadDiscriminator(Guid persistenceID)
|
||||
{
|
||||
byte[] discriminator = File.ReadAllBytes(Path.Combine(Directory.FullName, String.Format("{0}.discriminator", persistenceID.ToString())));
|
||||
return Encoding.UTF8.GetString(discriminator);
|
||||
}
|
||||
|
||||
private void WriteDiscriminator(Persistent persistent)
|
||||
{
|
||||
foreach (Index index in indeces)
|
||||
{
|
||||
index.Add(persistent);
|
||||
}
|
||||
|
||||
using (FileStream fileStream = new FileStream(Path.Combine(Directory.FullName,String.Format("{0}.discriminator",persistent.PersistenceID.ToString())),FileMode.Create))
|
||||
{
|
||||
byte[] discriminator = Encoding.UTF8.GetBytes(persistent.GetType().FullName);
|
||||
fileStream.Write(discriminator, 0, discriminator.Length);
|
||||
fileStream.Close();
|
||||
}
|
||||
|
||||
if (BaseStorage != null)
|
||||
BaseStorage.WriteDiscriminator(persistent);
|
||||
}
|
||||
|
||||
public bool Knows(Guid persistenceID)
|
||||
{
|
||||
return File.Exists(Path.Combine(Directory.FullName, String.Format("{0}.discriminator", persistenceID.ToString())));
|
||||
}
|
||||
|
||||
|
||||
public void Save(Persistent persistent)
|
||||
{
|
||||
try {
|
||||
WriteDiscriminator(persistent);
|
||||
} catch (Exception e)
|
||||
{
|
||||
Logger.Default.Log(e);
|
||||
RemoveDiscriminator(persistent.PersistenceID);
|
||||
|
||||
throw e;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Descriptor descriptor = StorageAdapter.OODB.GetDescriptor(persistent.GetType());
|
||||
|
||||
XmlDocument xmlDocument = new XmlDocument();
|
||||
XmlElement persistetInstance = xmlDocument.CreateElement("PersistetInstance");
|
||||
|
||||
xmlDocument.AppendChild(persistetInstance);
|
||||
|
||||
foreach (KeyValuePair<FieldInfo, FlatTypeMapping> flatField in descriptor.FlatMappings)
|
||||
{
|
||||
XmlElement fieldElement = xmlDocument.CreateElement("Field");
|
||||
fieldElement.SetAttribute("Name", flatField.Key.Name);
|
||||
fieldElement.AppendChild(flatField.Value.ToXml(xmlDocument, flatField.Key.GetValue(persistent)));
|
||||
|
||||
persistetInstance.AppendChild(fieldElement);
|
||||
}
|
||||
|
||||
xmlDocument.Save(Path.Combine(Directory.FullName, String.Format("{0}.xml", persistent.PersistenceID.ToString())));
|
||||
} catch (Exception e)
|
||||
{
|
||||
Logger.Default.Log(LogLevel.ERROR, "StorageAdapter.Save(): {0}", e);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void Restore(Persistent persistent)
|
||||
{
|
||||
Descriptor descriptor = StorageAdapter.OODB.GetDescriptor(persistent.GetType());
|
||||
|
||||
XmlDocument xmlDocument = new XmlDocument();
|
||||
xmlDocument.Load(Path.Combine(Directory.FullName, String.Format("{0}.xml", persistent.PersistenceID.ToString())));
|
||||
|
||||
foreach (XmlElement fieldElement in xmlDocument.SelectNodes("PersistetInstance/Field"))
|
||||
{
|
||||
try {
|
||||
FieldInfo fieldInfo = Descriptor.GetFieldInfo(fieldElement.GetAttribute("Name"));
|
||||
FlatTypeMapping flatTypeMapping = Descriptor.GetFlatTypeMapping(fieldInfo);
|
||||
|
||||
fieldInfo.SetValue(persistent, flatTypeMapping.FromXml(fieldElement.SelectSingleNode("Value") as XmlElement));
|
||||
|
||||
} catch (KeyNotFoundException)
|
||||
{
|
||||
Logger.Default.Log(LogLevel.WARNING, "data for unknown field {0} ignored", fieldElement.GetAttribute("Name"));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void Reference(Persistent persistent, FieldInfo referencing)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
public void UnReference(Persistent persistent, FieldInfo referencing)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public IEnumerable<KeyValuePair<Guid,Type>> List()
|
||||
{
|
||||
KeyValuePair<Guid,Type> create(FileInfo fileInfo)
|
||||
{
|
||||
Guid persistenceID = Guid.Parse(fileInfo.Name.Substring(0, fileInfo.Name.Length - fileInfo.Extension.Length));
|
||||
return new KeyValuePair<Guid, Type>(persistenceID,GetDiscriminator(persistenceID));
|
||||
}
|
||||
return Directory.GetFiles("*.discriminator").Select(create);
|
||||
}
|
||||
|
||||
public Type GetDiscriminator(Guid persistenceID)
|
||||
{
|
||||
String typeName = ReadDiscriminator(persistenceID);
|
||||
return StorageAdapter.OODB.LookupType(typeName);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
using System;
|
||||
namespace oodb.attributes
|
||||
{
|
||||
public class IndexedAttribute : Attribute
|
||||
{
|
||||
public IndexedAttribute()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
using System;
|
||||
namespace oodb.attributes
|
||||
{
|
||||
public class ReferencedFieldAttribute : Attribute
|
||||
{
|
||||
public String FieldName { get; }
|
||||
|
||||
public ReferencedFieldAttribute(String FieldName)
|
||||
{
|
||||
this.FieldName = FieldName;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
using System;
|
||||
namespace oodb.attributes
|
||||
{
|
||||
public class UniqueAttribute : Attribute
|
||||
{
|
||||
public UniqueAttribute()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using oodb.mapping;
|
||||
using System.Linq.Expressions;
|
||||
using sharp.logging;
|
||||
using oodb.attributes;
|
||||
using oodb.index;
|
||||
namespace oodb.descriptor
|
||||
{
|
||||
public class Descriptor
|
||||
{
|
||||
public OODB OODB { get; }
|
||||
public Type NativeType { get; }
|
||||
|
||||
public Descriptor BaseDescriptor { get; }
|
||||
public IEnumerable<KeyValuePair<FieldInfo, FlatTypeMapping>> FlatMappings => flatMappings;
|
||||
|
||||
|
||||
Dictionary<FieldInfo, FlatTypeMapping> flatMappings = new Dictionary<FieldInfo, FlatTypeMapping>();
|
||||
Dictionary<FieldInfo, ExtendedFieldHandling> extendedFieldHandlers = new Dictionary<FieldInfo, ExtendedFieldHandling>();
|
||||
|
||||
public Descriptor(OODB oodb,Type type)
|
||||
{
|
||||
OODB = oodb;
|
||||
NativeType = type;
|
||||
|
||||
OODB.descriptors.Add(NativeType, this);
|
||||
OODB.flatTypeMappings[type] = new ReferenceMapping(oodb, type);
|
||||
|
||||
if (type.BaseType != typeof(Persistent))
|
||||
{
|
||||
BaseDescriptor = OODB.GetDescriptor(type.BaseType);
|
||||
}
|
||||
|
||||
ConstructMappings();
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
foreach (ExtendedFieldHandling extendedFieldHandling in extendedFieldHandlers.Values)
|
||||
{
|
||||
extendedFieldHandling.Initialize();
|
||||
}
|
||||
}
|
||||
|
||||
public void Attach(Persistent persistent)
|
||||
{
|
||||
foreach (ExtendedFieldHandling extendedFieldHandling in extendedFieldHandlers.Values)
|
||||
{
|
||||
extendedFieldHandling.Attach(persistent);
|
||||
}
|
||||
}
|
||||
public void Detach(Persistent persistent)
|
||||
{
|
||||
foreach (ExtendedFieldHandling extendedFieldHandling in extendedFieldHandlers.Values)
|
||||
{
|
||||
extendedFieldHandling.Detach(persistent);
|
||||
}
|
||||
}
|
||||
|
||||
public FieldInfo GetFieldInfo(string fieldName)
|
||||
{
|
||||
foreach (FieldInfo fieldInfo in flatMappings.Keys)
|
||||
if (fieldInfo.Name.Equals(fieldName))
|
||||
return fieldInfo;
|
||||
|
||||
throw new KeyNotFoundException();
|
||||
}
|
||||
|
||||
public FlatTypeMapping GetFlatTypeMapping(FieldInfo fieldInfo)
|
||||
{
|
||||
return flatMappings[fieldInfo];
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void ConstructMappings()
|
||||
{
|
||||
if (BaseDescriptor != null)
|
||||
{
|
||||
foreach (FieldInfo baseField in BaseDescriptor.flatMappings.Keys)
|
||||
{
|
||||
flatMappings.Add(baseField, BaseDescriptor.flatMappings[baseField]);
|
||||
}
|
||||
foreach (FieldInfo baseField in BaseDescriptor.extendedFieldHandlers.Keys)
|
||||
{
|
||||
extendedFieldHandlers.Add(baseField, BaseDescriptor.extendedFieldHandlers[baseField]);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (FieldInfo fieldInfo in NativeType.GetFields(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic))
|
||||
{
|
||||
if (fieldInfo.GetCustomAttribute<IndexedAttribute>() != null)
|
||||
{
|
||||
OODB.StorageAdapter.GetSearchIndex(fieldInfo);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
FlatTypeMapping flatTypeMapping = OODB.GetFlatTypeMapping(fieldInfo.FieldType);
|
||||
flatMappings.Add(fieldInfo, flatTypeMapping);
|
||||
|
||||
if (fieldInfo.GetCustomAttribute<UniqueAttribute>() != null)
|
||||
{
|
||||
Unique uniqueIndex = new Unique(OODB, fieldInfo);
|
||||
}
|
||||
|
||||
} catch (KeyNotFoundException)
|
||||
{
|
||||
try {
|
||||
|
||||
ExtendedFieldHandling extendedFieldHandling = OODB.CreateExtendedFieldHandling(fieldInfo);
|
||||
extendedFieldHandlers.Add(fieldInfo, extendedFieldHandling);
|
||||
|
||||
} catch (NotSupportedException)
|
||||
{
|
||||
Logger.Default.Log("Ignoring unsupported Field {0}", fieldInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
using System;
|
||||
using System.Reflection;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml;
|
||||
using oodb.mapping;
|
||||
using System.IO;
|
||||
using System.Reflection.Emit;
|
||||
using System.Linq;
|
||||
namespace oodb.index
|
||||
{
|
||||
public abstract class Index
|
||||
{
|
||||
public OODB OODB { get; }
|
||||
public FieldInfo FieldInfo { get; }
|
||||
|
||||
public String FileName { get; }
|
||||
|
||||
public FlatTypeMapping ValueMapping { get; }
|
||||
public FlatTypeMapping StorageMapping { get; protected set; }
|
||||
|
||||
public Index(OODB oodb, FieldInfo fieldInfo)
|
||||
{
|
||||
OODB = oodb;
|
||||
FieldInfo = fieldInfo;
|
||||
|
||||
ValueMapping = OODB.GetFlatTypeMapping(fieldInfo.FieldType);
|
||||
StorageMapping = ValueMapping;
|
||||
|
||||
FileName = Path.Combine(
|
||||
OODB.StorageAdapter.GetTypeStorage(FieldInfo.DeclaringType).Directory.FullName,
|
||||
String.Format("index_{0}_{1}_{2}.xml", GetType().Name, FieldInfo.DeclaringType.Name, FieldInfo.Name)
|
||||
);
|
||||
|
||||
OODB.StorageAdapter.GetTypeStorage(fieldInfo.DeclaringType).AddIndex(this);
|
||||
|
||||
Prepare();
|
||||
|
||||
Load();
|
||||
}
|
||||
|
||||
protected abstract void Prepare();
|
||||
|
||||
public abstract IEnumerable<KeyValuePair<Guid, object>> RetrieveIndexValues();
|
||||
public abstract void RestoreIndexValues(IEnumerable<KeyValuePair<Guid, object>> indexValues);
|
||||
|
||||
public abstract void Add(Persistent persistent);
|
||||
public abstract void Remove(Guid persistenceID);
|
||||
|
||||
public void Remove(Persistent persistent)
|
||||
{
|
||||
Remove(persistent.PersistenceID);
|
||||
}
|
||||
|
||||
public abstract IEnumerable<Guid> Query();
|
||||
|
||||
|
||||
public void Load()
|
||||
{
|
||||
if (File.Exists(FileName))
|
||||
{
|
||||
XmlDocument xmlDocument = new XmlDocument();
|
||||
xmlDocument.Load(FileName);
|
||||
|
||||
RestoreIndexValues(
|
||||
xmlDocument.SelectNodes("/Index/Entry").Cast<XmlElement>().Select((entry) => new KeyValuePair<Guid, object>(Guid.Parse(entry.GetAttribute("PersistenceID")), StorageMapping.FromXml(entry.SelectSingleNode("Value") as XmlElement)))
|
||||
);
|
||||
}
|
||||
}
|
||||
public void Save()
|
||||
{
|
||||
XmlDocument xmlDocument = new XmlDocument();
|
||||
XmlElement indexElement = xmlDocument.CreateElement("Index");
|
||||
indexElement.SetAttribute("Type", GetType().FullName);
|
||||
|
||||
xmlDocument.AppendChild(indexElement);
|
||||
|
||||
|
||||
foreach (KeyValuePair<Guid,object> entry in RetrieveIndexValues())
|
||||
{
|
||||
XmlElement xmlEntry = xmlDocument.CreateElement("Entry");
|
||||
xmlEntry.SetAttribute("PersistenceID", entry.Key.ToString());
|
||||
xmlEntry.AppendChild(StorageMapping.ToXml(xmlDocument, entry.Value));
|
||||
indexElement.AppendChild(xmlEntry);
|
||||
}
|
||||
|
||||
xmlDocument.Save(FileName);
|
||||
}
|
||||
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return FileName.GetHashCode();
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is Index)
|
||||
{
|
||||
Index other = obj as Index;
|
||||
return FileName.Equals(other.FileName);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using oodb.mapping;
|
||||
using System.Linq;
|
||||
using System.Collections;
|
||||
namespace oodb.index
|
||||
{
|
||||
public class SearchIndex : Index
|
||||
{
|
||||
|
||||
Dictionary<string, ISet<Guid>> index = new Dictionary<string, ISet<Guid>>();
|
||||
Dictionary<Guid, string> reverseIndex = new Dictionary<Guid, string>();
|
||||
|
||||
public SearchIndex(OODB oodb,FieldInfo fieldInfo)
|
||||
:base(oodb,fieldInfo)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Prepare()
|
||||
{
|
||||
StorageMapping = OODB.GetFlatTypeMapping(typeof(string));
|
||||
}
|
||||
|
||||
public ISet<Guid> GetBucket(string value)
|
||||
{
|
||||
if (!index.ContainsKey(value))
|
||||
{
|
||||
index.Add(value, new HashSet<Guid>());
|
||||
}
|
||||
return index[value];
|
||||
}
|
||||
|
||||
public void Add(string value,Guid persistenceID)
|
||||
{
|
||||
if (reverseIndex.ContainsKey(persistenceID))
|
||||
{
|
||||
if (!reverseIndex[persistenceID].Equals(value))
|
||||
{
|
||||
GetBucket(reverseIndex[persistenceID]).Remove(persistenceID);
|
||||
GetBucket(value).Add(persistenceID);
|
||||
reverseIndex[persistenceID] = value;
|
||||
}
|
||||
} else {
|
||||
reverseIndex[persistenceID] = value;
|
||||
GetBucket(value).Add(persistenceID);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Add(Persistent persistent)
|
||||
{
|
||||
Add(ValueMapping.ToText(FieldInfo.GetValue(persistent)), persistent.PersistenceID);
|
||||
}
|
||||
|
||||
public override IEnumerable<Guid> Query()
|
||||
{
|
||||
return reverseIndex.Keys;
|
||||
}
|
||||
|
||||
public IEnumerable<Guid> QueryTextValue(string textValue)
|
||||
{
|
||||
return GetBucket(textValue);
|
||||
}
|
||||
public IEnumerable<Guid> Query(object value)
|
||||
{
|
||||
return QueryTextValue(ValueMapping.ToText(value));
|
||||
}
|
||||
|
||||
public IEnumerable<Guid> Query(Predicate predicate)
|
||||
{
|
||||
if (predicate.MatchesTextValues)
|
||||
{
|
||||
return reverseIndex.Where((kvp) => predicate.TextMatch(kvp.Value)).Select((kvp) => kvp.Key);
|
||||
} else
|
||||
{
|
||||
return reverseIndex.Where((kvp) => predicate.Match(ValueMapping.FromText(kvp.Value))).Select((kvp) => kvp.Key);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Remove(Guid persistenceID)
|
||||
{
|
||||
if (reverseIndex.ContainsKey(persistenceID))
|
||||
{
|
||||
GetBucket(reverseIndex[persistenceID]).Remove(persistenceID);
|
||||
reverseIndex.Remove(persistenceID);
|
||||
}
|
||||
}
|
||||
|
||||
public override void RestoreIndexValues(IEnumerable<KeyValuePair<Guid, object>> indexValues)
|
||||
{
|
||||
reverseIndex.Clear();
|
||||
index.Clear();
|
||||
|
||||
foreach (KeyValuePair<Guid,object> kvp in indexValues)
|
||||
{
|
||||
Add(kvp.Value as string, kvp.Key);
|
||||
}
|
||||
}
|
||||
|
||||
public override IEnumerable<KeyValuePair<Guid, object>> RetrieveIndexValues()
|
||||
{
|
||||
return reverseIndex.Select((x) => new KeyValuePair<Guid, object>(x.Key, x.Value));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
using System;
|
||||
using System.Reflection;
|
||||
using System.Collections.Generic;
|
||||
namespace oodb.index
|
||||
{
|
||||
public class Unique : Index
|
||||
{
|
||||
|
||||
Dictionary<Guid, object> uniqueForward = new Dictionary<Guid, object>();
|
||||
Dictionary<object, Guid> uniqueReverse = new Dictionary<object, Guid>();
|
||||
|
||||
public Unique(OODB oodb,FieldInfo fieldInfo)
|
||||
:base(oodb,fieldInfo)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Prepare()
|
||||
{
|
||||
}
|
||||
|
||||
public override void Add(Persistent persistent)
|
||||
{
|
||||
object value = FieldInfo.GetValue(persistent);
|
||||
Guid persistenceId = persistent.PersistenceID;
|
||||
|
||||
if (uniqueReverse.ContainsKey(value))
|
||||
{
|
||||
if (uniqueReverse[value].Equals(persistenceId))
|
||||
return;
|
||||
|
||||
throw new ArgumentException();
|
||||
}
|
||||
|
||||
if (uniqueForward.ContainsKey(persistenceId))
|
||||
Remove(persistenceId);
|
||||
|
||||
uniqueForward.Add(persistenceId, value);
|
||||
uniqueReverse.Add(value, persistenceId);
|
||||
}
|
||||
|
||||
public override IEnumerable<Guid> Query()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void Remove(Guid persistenceID)
|
||||
{
|
||||
if (uniqueForward.ContainsKey(persistenceID))
|
||||
{
|
||||
uniqueReverse.Remove(uniqueForward[persistenceID]);
|
||||
uniqueForward.Remove(persistenceID);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override void RestoreIndexValues(IEnumerable<KeyValuePair<Guid, object>> indexValues)
|
||||
{
|
||||
uniqueForward.Clear();
|
||||
uniqueReverse.Clear();
|
||||
|
||||
foreach (KeyValuePair<Guid,object> entry in indexValues)
|
||||
{
|
||||
uniqueForward.Add(entry.Key, entry.Value);
|
||||
uniqueReverse.Add(entry.Value, entry.Key);
|
||||
}
|
||||
|
||||
}
|
||||
public override IEnumerable<KeyValuePair<Guid, object>> RetrieveIndexValues()
|
||||
{
|
||||
return uniqueForward;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
using System;
|
||||
using System.Xml;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections;
|
||||
|
||||
namespace oodb.mapping
|
||||
{
|
||||
public class ArrayMapping : ListMapping
|
||||
{
|
||||
public ArrayMapping(OODB oodb,Type type)
|
||||
:base(oodb,typeof(List<>).MakeGenericType(type.GetElementType()))
|
||||
{
|
||||
}
|
||||
|
||||
public override XmlElement ToXml(XmlDocument xmlDocument, object value)
|
||||
{
|
||||
IList list = value as IList;
|
||||
Array array = Array.CreateInstance(ElementMapping.NativeType, list.Count);
|
||||
(list as IList).CopyTo(array, 0);
|
||||
|
||||
return base.ToXml(xmlDocument,list);
|
||||
}
|
||||
public override object FromXml(XmlElement xmlValue)
|
||||
{
|
||||
IList list = base.FromXml(xmlValue) as IList;
|
||||
Array array = Array.CreateInstance(ElementMapping.NativeType, list.Count) as Array;
|
||||
list.CopyTo(array, list.Count);
|
||||
return array;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
using System;
|
||||
using System.Xml;
|
||||
using System.Globalization;
|
||||
|
||||
namespace oodb.mapping
|
||||
{
|
||||
public class DoubleMapping : NaiveMapping
|
||||
{
|
||||
public DoubleMapping(OODB oodb)
|
||||
: base(oodb, typeof(double))
|
||||
{
|
||||
}
|
||||
|
||||
public override object FromText(string text)
|
||||
{
|
||||
double iValue = double.Parse(text, CultureInfo.InvariantCulture);
|
||||
if (NativeType != typeof(double))
|
||||
{
|
||||
return Convert.ChangeType(iValue, NativeType);
|
||||
}
|
||||
return iValue;
|
||||
}
|
||||
|
||||
public override string ToText(object value)
|
||||
{
|
||||
double iValue = (double)value;
|
||||
return iValue.ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
using System;
|
||||
using System.Reflection;
|
||||
using System.Xml;
|
||||
namespace oodb.mapping
|
||||
{
|
||||
public abstract class ExtendedFieldHandling
|
||||
{
|
||||
public OODB OODB { get; }
|
||||
public FieldInfo FieldInfo { get; }
|
||||
|
||||
public ExtendedFieldHandling(OODB oodb,FieldInfo fieldInfo)
|
||||
{
|
||||
OODB = oodb;
|
||||
FieldInfo = fieldInfo;
|
||||
}
|
||||
|
||||
public virtual void Initialize(){}
|
||||
|
||||
public abstract void Save(XmlElement persistenceElement,Persistent persistent);
|
||||
public abstract void Load(XmlElement persistenceElement,Persistent persistent);
|
||||
|
||||
public abstract void Attach(Persistent persistent);
|
||||
public abstract void Detach(Persistent persistent);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
using System;
|
||||
using System.Xml;
|
||||
|
||||
namespace oodb.mapping
|
||||
{
|
||||
public abstract class FlatTypeMapping
|
||||
{
|
||||
public OODB OODB { get; }
|
||||
public Type NativeType { get; }
|
||||
|
||||
public FlatTypeMapping(OODB oodb, Type nativeType)
|
||||
{
|
||||
OODB = oodb;
|
||||
NativeType = nativeType;
|
||||
}
|
||||
|
||||
public XmlElement CreateEmptyValueElement(XmlDocument xmlDocument)
|
||||
{
|
||||
XmlElement value = xmlDocument.CreateElement("Value");
|
||||
value.SetAttribute("Type", NativeType.FullName);
|
||||
return value;
|
||||
}
|
||||
|
||||
public abstract XmlElement ToXml(XmlDocument xmlDocument, object value);
|
||||
public abstract object FromXml(XmlElement xmlValue);
|
||||
|
||||
public abstract String ToText(object value);
|
||||
public abstract object FromText(string text);
|
||||
}
|
||||
|
||||
public abstract class NaiveMapping : FlatTypeMapping
|
||||
{
|
||||
public NaiveMapping(OODB oodb, Type nativeType)
|
||||
:base(oodb,nativeType)
|
||||
{
|
||||
}
|
||||
|
||||
public override object FromXml(XmlElement xmlValue)
|
||||
{
|
||||
if (!NativeType.FullName.Equals(xmlValue.GetAttribute("Type")))
|
||||
throw new ArgumentException("Type != NativeType", nameof(xmlValue));
|
||||
|
||||
return FromText(xmlValue.InnerText);
|
||||
}
|
||||
|
||||
public override XmlElement ToXml(XmlDocument xmlDocument, object value)
|
||||
{
|
||||
XmlElement valueElement = CreateEmptyValueElement(xmlDocument);
|
||||
if (value != null)
|
||||
valueElement.InnerText = ToText(value);
|
||||
|
||||
return valueElement;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
using System;
|
||||
using System.Xml;
|
||||
using System.Globalization;
|
||||
|
||||
namespace oodb.mapping
|
||||
{
|
||||
public class IntegerMapping : NaiveMapping
|
||||
{
|
||||
public IntegerMapping(OODB oodb)
|
||||
: base(oodb, typeof(int))
|
||||
{
|
||||
}
|
||||
|
||||
public override object FromText(String text)
|
||||
{
|
||||
int iValue = int.Parse(text, CultureInfo.InvariantCulture);
|
||||
if (NativeType != typeof(int))
|
||||
{
|
||||
return Convert.ChangeType(iValue, NativeType);
|
||||
}
|
||||
return iValue;
|
||||
}
|
||||
|
||||
public override string ToText(object value)
|
||||
{
|
||||
int iValue = (int)value;
|
||||
return iValue.ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
using System;
|
||||
using System.Xml;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace oodb.mapping
|
||||
{
|
||||
public class ListMapping : NaiveMapping
|
||||
{
|
||||
public FlatTypeMapping ElementMapping { get; }
|
||||
|
||||
public ListMapping(OODB oodb, Type type)
|
||||
: base(oodb, type)
|
||||
{
|
||||
ElementMapping = OODB.GetFlatTypeMapping(type.GetGenericArguments()[0]);
|
||||
}
|
||||
|
||||
public override object FromXml(XmlElement xmlValue)
|
||||
{
|
||||
if (!NativeType.FullName.Equals(xmlValue.GetAttribute("Type")))
|
||||
throw new ArgumentException("Type != NativeType", nameof(xmlValue));
|
||||
|
||||
IList list = Activator.CreateInstance(typeof(List<>).MakeGenericType(ElementMapping.NativeType)) as IList;
|
||||
foreach (XmlNode elementNode in xmlValue.ChildNodes)
|
||||
{
|
||||
if ((elementNode is XmlElement) && ((((XmlElement)elementNode).Name.Equals("Value"))))
|
||||
{
|
||||
list.Add(ElementMapping.FromXml(elementNode as XmlElement));
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public override XmlElement ToXml(XmlDocument xmlDocument, object value)
|
||||
{
|
||||
XmlElement valueElement = CreateEmptyValueElement(xmlDocument);
|
||||
|
||||
IList list = value as IList;
|
||||
|
||||
for (int n = 0; n < list.Count; n++)
|
||||
{
|
||||
valueElement.AppendChild(ElementMapping.ToXml(xmlDocument, list[n]));
|
||||
}
|
||||
|
||||
return valueElement;
|
||||
}
|
||||
|
||||
public override string ToText(object value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override object FromText(string text)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
using System;
|
||||
using System.Xml;
|
||||
|
||||
namespace oodb.mapping
|
||||
{
|
||||
public class ReferenceMapping : NaiveMapping
|
||||
{
|
||||
public ReferenceMapping(OODB oodb, Type type)
|
||||
: base(oodb, type)
|
||||
{
|
||||
}
|
||||
|
||||
public override object FromText(string text)
|
||||
{
|
||||
if (String.Empty.Equals(text))
|
||||
return null;
|
||||
|
||||
Guid persistenceID = Guid.Parse(text);
|
||||
return OODB.Load(NativeType, persistenceID);
|
||||
}
|
||||
public override string ToText(object value)
|
||||
{
|
||||
Persistent reference = value as Persistent;
|
||||
|
||||
if (reference == null)
|
||||
{
|
||||
return Guid.Empty.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
string text = reference.PersistenceID.ToString();
|
||||
OODB.Ensure(reference);
|
||||
return text;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
using System;
|
||||
using System.Xml;
|
||||
|
||||
namespace oodb.mapping
|
||||
{
|
||||
public class StringMapping : NaiveMapping
|
||||
{
|
||||
public StringMapping(OODB oodb)
|
||||
: base(oodb, typeof(string))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override object FromText(string text)
|
||||
{
|
||||
return text;
|
||||
}
|
||||
|
||||
public override string ToText(object value)
|
||||
{
|
||||
return value as string;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
using System;
|
||||
using System.Reflection;
|
||||
using System.Xml;
|
||||
using oodb.attributes;
|
||||
|
||||
namespace oodb.mapping.collections
|
||||
{
|
||||
public class ISetExtendedHandling : ExtendedFieldHandling
|
||||
{
|
||||
public Type ReferencedType { get; }
|
||||
public FieldInfo ReferencedField { get; protected set; }
|
||||
|
||||
public Type ImplementationType { get; }
|
||||
|
||||
public ISetExtendedHandling(OODB oodb,FieldInfo fieldInfo)
|
||||
:base(oodb,fieldInfo)
|
||||
{
|
||||
ReferencedType = fieldInfo.FieldType.GetGenericArguments()[0];
|
||||
ImplementationType = typeof(ISetImplementation<>).MakeGenericType(ReferencedType);
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
ReferencedFieldAttribute referencedFieldAttribute = FieldInfo.GetCustomAttribute<ReferencedFieldAttribute>();
|
||||
string refFieldName = referencedFieldAttribute != null ? referencedFieldAttribute.FieldName : FieldInfo.DeclaringType.Name;
|
||||
ReferencedField = ReferencedType.GetField(refFieldName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
|
||||
|
||||
OODB.StorageAdapter.GetSearchIndex(ReferencedField);
|
||||
}
|
||||
|
||||
public override void Attach(Persistent persistent)
|
||||
{
|
||||
object iset = FieldInfo.GetValue(persistent);
|
||||
|
||||
if (ImplementationType != iset.GetType())
|
||||
{
|
||||
object impl = Activator.CreateInstance(ImplementationType,OODB,FieldInfo,persistent);
|
||||
FieldInfo.SetValue(persistent, impl);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public override void Detach(Persistent persistent)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Load(XmlElement persistenceElement, Persistent persistent)
|
||||
{
|
||||
Attach(persistent);
|
||||
}
|
||||
|
||||
public override void Save(XmlElement persistenceElement, Persistent persistent)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,150 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using oodb.attributes;
|
||||
using oodb.index;
|
||||
using System.Linq;
|
||||
|
||||
namespace oodb.mapping.collections
|
||||
{
|
||||
public class ISetImplementation<T> : ISet<T> where T: Persistent
|
||||
{
|
||||
public OODB OODB { get; }
|
||||
public FieldInfo FieldInfo { get; }
|
||||
|
||||
public Persistent Owner { get; }
|
||||
|
||||
public FieldInfo ReferencedField { get; }
|
||||
public Type ReferencedType { get; }
|
||||
|
||||
public SearchIndex SearchIndex { get; }
|
||||
|
||||
public ISetImplementation(OODB oodb,FieldInfo fieldInfo,Persistent owner)
|
||||
{
|
||||
OODB = oodb;
|
||||
FieldInfo = fieldInfo;
|
||||
Owner = owner;
|
||||
|
||||
ReferencedType = fieldInfo.FieldType.GetGenericArguments()[0];
|
||||
|
||||
ReferencedFieldAttribute referencedFieldAttribute = FieldInfo.GetCustomAttribute<ReferencedFieldAttribute>();
|
||||
string refFieldName = referencedFieldAttribute != null ? referencedFieldAttribute.FieldName : FieldInfo.DeclaringType.Name;
|
||||
ReferencedField = ReferencedType.GetField(refFieldName, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
|
||||
|
||||
SearchIndex = OODB.StorageAdapter.GetSearchIndex(ReferencedField);
|
||||
}
|
||||
|
||||
public IEnumerable<Guid> ElementPersistenceIDs => SearchIndex.QueryTextValue(Owner.PersistenceID.ToString());
|
||||
|
||||
public int Count => ElementPersistenceIDs.Count();
|
||||
public bool IsReadOnly => false;
|
||||
|
||||
public bool Add(T item)
|
||||
{
|
||||
if (!Contains(item))
|
||||
{
|
||||
ReferencedField.SetValue(item, Owner);
|
||||
OODB.Save(item);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool Remove(T item)
|
||||
{
|
||||
if (Contains(item))
|
||||
{
|
||||
ReferencedField.SetValue(item, null);
|
||||
OODB.Save(item);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
foreach (T item in this)
|
||||
Remove(item);
|
||||
}
|
||||
|
||||
public bool Contains(T item)
|
||||
{
|
||||
Persistent persistentItem = item as Persistent;
|
||||
foreach (Guid elementID in ElementPersistenceIDs)
|
||||
if (elementID.Equals(persistentItem.PersistenceID))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public void CopyTo(T[] array, int arrayIndex)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void ExceptWith(IEnumerable<T> other)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return ElementPersistenceIDs.Select((id) => OODB.Load<T>(id)).GetEnumerator();
|
||||
}
|
||||
|
||||
public void IntersectWith(IEnumerable<T> other)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool IsProperSubsetOf(IEnumerable<T> other)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool IsProperSupersetOf(IEnumerable<T> other)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool IsSubsetOf(IEnumerable<T> other)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool IsSupersetOf(IEnumerable<T> other)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool Overlaps(IEnumerable<T> other)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool SetEquals(IEnumerable<T> other)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void SymmetricExceptWith(IEnumerable<T> other)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void UnionWith(IEnumerable<T> other)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
void ICollection<T>.Add(T item)
|
||||
{
|
||||
Add(item);
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using oodb.descriptor;
|
||||
using System.Dynamic;
|
||||
namespace oodb.persistence
|
||||
{
|
||||
public class PersistenceCache
|
||||
{
|
||||
public OODB OODB { get; }
|
||||
|
||||
|
||||
Dictionary<Type, TypeCache> typeCaches = new Dictionary<Type, TypeCache>();
|
||||
|
||||
|
||||
public PersistenceCache(OODB oodb)
|
||||
{
|
||||
OODB = oodb;
|
||||
}
|
||||
|
||||
private TypeCache GetTypeCache(Type type)
|
||||
{
|
||||
if (!typeCaches.ContainsKey(type))
|
||||
typeCaches[type] = new TypeCache(this,type);
|
||||
return typeCaches[type];
|
||||
}
|
||||
|
||||
public Persistent Get(Type type,Guid persistenceID)
|
||||
{
|
||||
return GetTypeCache(type).Get(persistenceID);
|
||||
}
|
||||
|
||||
public void Touch(Persistent persistent)
|
||||
{
|
||||
GetTypeCache(persistent.GetType()).Touch(persistent);
|
||||
}
|
||||
|
||||
public void Remove(Persistent persistent)
|
||||
{
|
||||
GetTypeCache(persistent.GetType()).Remove(persistent);
|
||||
}
|
||||
|
||||
|
||||
|
||||
class TypeCache
|
||||
{
|
||||
PersistenceCache PersistenceCache { get; }
|
||||
TypeCache BaseCache { get; }
|
||||
|
||||
Type CacheType { get; }
|
||||
|
||||
Descriptor Descriptor { get; }
|
||||
|
||||
Dictionary<Guid, WeakReference> cache = new Dictionary<Guid, WeakReference>();
|
||||
|
||||
public TypeCache(PersistenceCache persistenceCache,Type type)
|
||||
{
|
||||
PersistenceCache = persistenceCache;
|
||||
CacheType = type;
|
||||
Descriptor = persistenceCache.OODB.GetDescriptor(type);
|
||||
|
||||
if (Descriptor.BaseDescriptor != null)
|
||||
BaseCache = persistenceCache.GetTypeCache(Descriptor.BaseDescriptor.NativeType);
|
||||
}
|
||||
|
||||
public Persistent Get(Guid persistenceID)
|
||||
{
|
||||
WeakReference weakReference = cache[persistenceID];
|
||||
if (!weakReference.IsAlive)
|
||||
{
|
||||
Remove(persistenceID);
|
||||
throw new KeyNotFoundException(persistenceID.ToString());
|
||||
}
|
||||
return weakReference.Target as Persistent;
|
||||
}
|
||||
|
||||
public void Touch(Persistent persistent)
|
||||
{
|
||||
cache[persistent.PersistenceID] = new WeakReference(persistent);
|
||||
if (Descriptor.BaseDescriptor != null)
|
||||
PersistenceCache.GetTypeCache(Descriptor.BaseDescriptor.NativeType).Touch(persistent);
|
||||
}
|
||||
|
||||
public void Remove(Persistent persistent)
|
||||
{
|
||||
Remove(persistent.PersistenceID);
|
||||
}
|
||||
public void Remove(Guid persistenceID)
|
||||
{
|
||||
cache.Remove(persistenceID);
|
||||
if (Descriptor.BaseDescriptor != null)
|
||||
{
|
||||
PersistenceCache.GetTypeCache(Descriptor.BaseDescriptor.NativeType).Remove(persistenceID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
|
||||
<ProjectGuid>{FF9FA8D2-5E89-4609-83F0-B9512DF777BE}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<RootNamespace>oodb</RootNamespace>
|
||||
<AssemblyName>sharp-oodb</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug</OutputPath>
|
||||
<DefineConstants>DEBUG;</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<ExternalConsole>true</ExternalConsole>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release</OutputPath>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<ExternalConsole>true</ExternalConsole>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="OODB.cs" />
|
||||
<Compile Include="mapping\FlatTypeMapping.cs" />
|
||||
<Compile Include="Persistent.cs" />
|
||||
<Compile Include="descriptor\Descriptor.cs" />
|
||||
<Compile Include="mapping\ListMapping.cs" />
|
||||
<Compile Include="mapping\StringMapping.cs" />
|
||||
<Compile Include="mapping\IntegerMapping.cs" />
|
||||
<Compile Include="mapping\DoubleMapping.cs" />
|
||||
<Compile Include="mapping\ReferenceMapping.cs" />
|
||||
<Compile Include="persistence\PersistenceCache.cs" />
|
||||
<Compile Include="StorageAdapter.cs" />
|
||||
<Compile Include="mapping\ArrayMapping.cs" />
|
||||
<Compile Include="index\Index.cs" />
|
||||
<Compile Include="index\Unique.cs" />
|
||||
<Compile Include="attributes\UniqueAttribute.cs" />
|
||||
<Compile Include="attributes\ReferencedFieldAttribute.cs" />
|
||||
<Compile Include="mapping\collections\ISetImplementation.cs" />
|
||||
<Compile Include="Query.cs" />
|
||||
<Compile Include="index\SearchIndex.cs" />
|
||||
<Compile Include="mapping\ExtendedFieldHandling.cs" />
|
||||
<Compile Include="mapping\collections\ISetExtendedHandling.cs" />
|
||||
<Compile Include="attributes\IndexedAttribute.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="mapping\" />
|
||||
<Folder Include="descriptor\" />
|
||||
<Folder Include="persistence\" />
|
||||
<Folder Include="index\" />
|
||||
<Folder Include="attributes\" />
|
||||
<Folder Include="mapping\collections\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\sharp-logging\sharp.logging.csproj">
|
||||
<Project>{D471A566-9FB6-41B2-A777-3C32874ECD0E}</Project>
|
||||
<Name>sharp.logging</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
Loading…
Reference in New Issue