Browse Source

comit: import project

HOME 5 years ago
parent
commit
1c5e2ecde9

+ 92 - 0
FsDb.Test/FsDb.Test.csproj

@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{34388A81-2637-46B3-BC69-3324512D21C7}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>FsDb.Test</RootNamespace>
+    <AssemblyName>FsDb.Test</AssemblyName>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <SccProjectName>Svn</SccProjectName>
+    <SccLocalPath>Svn</SccLocalPath>
+    <SccAuxPath>Svn</SccAuxPath>
+    <SccProvider>SubversionScc</SccProvider>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>bin\x86\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
+    <OutputPath>bin\x86\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="Newtonsoft.Json">
+      <HintPath>..\packages\Newtonsoft.Json.6.0.5\lib\net35\Newtonsoft.Json.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Program.cs">
+      <SubType>
+      </SubType>
+    </Compile>
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Utility.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\FsDb\FsDb.csproj">
+      <Project>{ddb5e1f5-0eb0-49a1-918d-fc4b2b9bc6e5}</Project>
+      <Name>FsDb</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>

+ 115 - 0
FsDb.Test/Program.cs

@@ -0,0 +1,115 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Linq;
+using Newtonsoft.Json;
+
+namespace FsDb.Test
+{
+    class Program
+    {
+        static void Main(string[] args)
+        {
+            var db = new FsDbEngine(
+                AppDomain.CurrentDomain.BaseDirectory
+                         .CombineLocalPath("data")
+            );
+
+            var colBook = db.GetCollection<Book>();
+            var colTag = db.GetCollection<Tag>();
+            var colBookTag = db.GetCollection<BookTag>();
+
+            var book = new Book();
+            var tag = new Tag();
+            var booktag = new BookTag();
+
+            colBook.Add(book);
+            colTag.Add(tag);
+
+            booktag.Book = book;
+            booktag.Tag = tag;
+
+            colBookTag.Add(booktag);
+
+            colBook.Compress();
+            colTag.Compress();
+            colBookTag.Compress();
+        }
+    }
+
+    class Book : FsDbEntityBase
+    {
+        public string Name { get; set; }
+        public string Author { get; set; }
+        public decimal Price { get; set; }
+
+        public float Rank { get; set; }
+
+        [JsonIgnore]
+        public FsDbEntitySet<BookTag> BookTag { private set; get; }
+
+        public Book()
+        {
+            BookTag = new FsDbEntitySet<BookTag>(
+                this, p => p.BookID == this.ID
+                    , p => p.BookID = this.ID
+            );
+        }
+    }
+
+    class Tag : FsDbEntityBase
+    {
+        public int Name { get; set; }
+        public float Rank { get; set; }
+
+        [JsonIgnore]
+        public FsDbEntitySet<BookTag> BookTag { private set; get; }
+
+        public Tag()
+        {
+            BookTag = new FsDbEntitySet<BookTag>(
+                this, p => p.TagID == this.ID
+                    , p => p.TagID = this.ID
+            );
+        }
+    }
+
+    class BookTag : FsDbEntityBase
+    {
+        public int BookID { get; set; }
+        public int TagID { get; set; }
+        public float Rank { get; set; }
+
+        private FsDbEntityRef<Book> m_Book;
+        private FsDbEntityRef<Tag> m_Tag;
+
+        public BookTag()
+        {
+            m_Book = new FsDbEntityRef<Book>(
+                this,
+                 p => p.ID == this.BookID
+                 , p => this.BookID = p.ID
+            );
+
+            m_Tag = new FsDbEntityRef<Tag>(
+                this,
+                 p => p.ID == this.TagID
+                 , p => this.TagID = p.ID
+            );
+        }
+
+        [JsonIgnore]
+        public Book Book
+        {
+            get { return m_Book.Entity; }
+            set { m_Book.Entity = value; }
+        }
+
+        [JsonIgnore]
+        public Tag Tag
+        {
+            get { return m_Tag.Entity; }
+            set { m_Tag.Entity = value; }
+        }
+    }
+}

+ 36 - 0
FsDb.Test/Properties/AssemblyInfo.cs

@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// 有关程序集的常规信息通过以下
+// 特性集控制。更改这些特性值可修改
+// 与程序集关联的信息。
+[assembly: AssemblyTitle("FsDb.Test")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Microsoft")]
+[assembly: AssemblyProduct("FsDb.Test")]
+[assembly: AssemblyCopyright("Copyright © Microsoft 2013")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// 将 ComVisible 设置为 false 使此程序集中的类型
+// 对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型,
+// 则将该类型上的 ComVisible 特性设置为 true。
+[assembly: ComVisible(false)]
+
+// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
+[assembly: Guid("2a7cb7e9-86e8-4627-ae7f-fb60ad901ec5")]
+
+// 程序集的版本信息由下面四个值组成:
+//
+//      主版本
+//      次版本 
+//      生成号
+//      修订号
+//
+// 可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
+// 方法是按如下所示使用“*”:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

+ 29 - 0
FsDb.Test/Utility.cs

@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using System.Linq;
+
+namespace FsDb.Test
+{
+    internal static class Utility
+    {
+        public static string CombineLocalPath(this string me, params string[] nexts)
+        {
+            if (me == null || nexts.Length == 0)
+                throw new ArgumentNullException();
+
+            string dsc = Path.DirectorySeparatorChar.ToString();
+
+            var lst = nexts.ToList();
+
+            lst.Insert(0, me);
+
+            return string.Join(
+                    dsc
+                    , lst.ToArray()
+                )
+            ;
+        }
+    }
+}

+ 4 - 0
FsDb.Test/packages.config

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="Newtonsoft.Json" version="6.0.5" targetFramework="net35" />
+</packages>

+ 40 - 0
FsDb.sln

@@ -0,0 +1,40 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2012
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FsDb", "FsDb\FsDb.csproj", "{DDB5E1F5-0EB0-49A1-918D-FC4B2B9BC6E5}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FsDb.Test", "FsDb.Test\FsDb.Test.csproj", "{34388A81-2637-46B3-BC69-3324512D21C7}"
+EndProject
+Global
+	GlobalSection(SubversionScc) = preSolution
+		Svn-Managed = True
+		Manager = AnkhSVN - Subversion Support for Visual Studio
+	EndGlobalSection
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Debug|x86 = Debug|x86
+		Release|Any CPU = Release|Any CPU
+		Release|x86 = Release|x86
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{DDB5E1F5-0EB0-49A1-918D-FC4B2B9BC6E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{DDB5E1F5-0EB0-49A1-918D-FC4B2B9BC6E5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{DDB5E1F5-0EB0-49A1-918D-FC4B2B9BC6E5}.Debug|x86.ActiveCfg = Debug|x86
+		{DDB5E1F5-0EB0-49A1-918D-FC4B2B9BC6E5}.Debug|x86.Build.0 = Debug|x86
+		{DDB5E1F5-0EB0-49A1-918D-FC4B2B9BC6E5}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{DDB5E1F5-0EB0-49A1-918D-FC4B2B9BC6E5}.Release|Any CPU.Build.0 = Release|Any CPU
+		{DDB5E1F5-0EB0-49A1-918D-FC4B2B9BC6E5}.Release|x86.ActiveCfg = Release|x86
+		{DDB5E1F5-0EB0-49A1-918D-FC4B2B9BC6E5}.Release|x86.Build.0 = Release|x86
+		{34388A81-2637-46B3-BC69-3324512D21C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{34388A81-2637-46B3-BC69-3324512D21C7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{34388A81-2637-46B3-BC69-3324512D21C7}.Debug|x86.ActiveCfg = Debug|x86
+		{34388A81-2637-46B3-BC69-3324512D21C7}.Debug|x86.Build.0 = Debug|x86
+		{34388A81-2637-46B3-BC69-3324512D21C7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{34388A81-2637-46B3-BC69-3324512D21C7}.Release|Any CPU.Build.0 = Release|Any CPU
+		{34388A81-2637-46B3-BC69-3324512D21C7}.Release|x86.ActiveCfg = Release|x86
+		{34388A81-2637-46B3-BC69-3324512D21C7}.Release|x86.Build.0 = Release|x86
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal

+ 84 - 0
FsDb/FsDb.csproj

@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{DDB5E1F5-0EB0-49A1-918D-FC4B2B9BC6E5}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>FsDb</RootNamespace>
+    <AssemblyName>FsDb</AssemblyName>
+    <TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <SccProjectName>Svn</SccProjectName>
+    <SccLocalPath>Svn</SccLocalPath>
+    <SccAuxPath>Svn</SccAuxPath>
+    <SccProvider>SubversionScc</SccProvider>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>bin\x86\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
+    <OutputPath>bin\x86\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="ICSharpCode.SharpZipLib">
+      <HintPath>..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll</HintPath>
+    </Reference>
+    <Reference Include="Newtonsoft.Json">
+      <HintPath>..\packages\Newtonsoft.Json.6.0.5\lib\net20\Newtonsoft.Json.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="FsDbEngine.cs" />
+    <Compile Include="LinqBridge-1.3.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Utility.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>

+ 596 - 0
FsDb/FsDbEngine.cs

@@ -0,0 +1,596 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Linq;
+using System.IO;
+using System.Collections;
+
+using Newtonsoft.Json;
+using ICSharpCode.SharpZipLib.GZip;
+using System.ComponentModel;
+
+namespace FsDb
+{
+    public class FsDbEngine
+    {
+        //---- consts
+
+        private const string ENTITY_FILE_EX = ".Json";
+        private const string IDENTITY_FILE_EX = ".FsDbIdentity";
+        private const string COMPRESS_FILE_EX = ".FsDb.gz";
+
+        //---- props
+
+        private bool m_MaxinumCompress = true;
+        private bool m_EnableAutoCompress = true;
+        private int m_FileCountToAutoCompress = 50;
+        private bool m_OpenAsReadonly;
+
+        protected bool MaxinumCompress
+        {
+            get { return m_MaxinumCompress; }
+            set { m_MaxinumCompress = value; }
+        }
+
+        protected bool EnableAutoCompress
+        {
+            get { return m_EnableAutoCompress; }
+            set { m_EnableAutoCompress = value; }
+        }
+
+        protected int FileCountToAutoCompress
+        {
+            get { return m_FileCountToAutoCompress; }
+            set { m_FileCountToAutoCompress = value; }
+        }
+
+        public event CancelEventHandler OnBeforeAutoCompress;
+        public event EventHandler OnAfterAutoCompress;
+
+        //---- ctors
+
+        public FsDbEngine(string dbFolderPath, bool openAsReadonly = false)
+        {
+            m_OpenAsReadonly = openAsReadonly;
+
+            if (Directory.Exists(dbFolderPath) == false && m_OpenAsReadonly == false)
+            {
+                Directory.CreateDirectory(dbFolderPath);
+                OnCreate();
+            }
+
+            m_strDbFolderPath = dbFolderPath;
+
+            //lazy load...
+            m_dicCollections = new Dictionary<Type, object>();
+        }
+
+
+        //---- internals
+
+        private string m_strDbFolderPath;
+
+        private Dictionary<Type, object> m_dicCollections;
+
+        //---- internal commons
+
+        private T LoadEntityFromJson<T>(string p) where T : FsDbEntityBase, new()
+        {
+            //load user data
+            var ud = JsonConvert.DeserializeObject<T>(p);
+
+            //load system data
+            var sd = new { IsDeleted = false, ID = 0 };
+            sd = JsonConvert.DeserializeAnonymousType(p, sd);
+
+            ud.ID = sd.ID;
+            ud.IsDeleted = sd.IsDeleted;
+            ud.EngineInstance = this;
+
+            return ud;
+        }
+
+        private static void OverrodeColl<T>(FsDbCollection<T> coll, T p) where T : FsDbEntityBase, new()
+        {
+            var oe = coll.InternalContainer.FirstOrDefault(q => q.ID == p.ID);
+            if (oe == null)
+                coll.InternalContainer.Add(p);
+            else
+                coll.InternalContainer[coll.InternalContainer.IndexOf(oe)] = p;
+        }
+
+        private static byte[] PackColl<T>(FsDbCollection<T> coll) where T : FsDbEntityBase, new()
+        {
+            var msPack = new MemoryStream();
+
+            var bw = new BinaryWriter(msPack);
+
+            //identity
+            bw.Write(coll.CurrentIdentity);
+            //count
+            bw.Write(coll.Count);
+            foreach (var item in coll)
+            {
+                var buf = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(item));
+
+                //length-of-bytes
+                bw.Write(buf.Length);
+                //json-utf8-bytes
+                bw.Write(buf);
+            }
+
+            bw.Flush();
+
+            return msPack.ToArray();
+        }
+
+        private void UnPackColl<T>(FsDbCollection<T> coll, byte[] bufPack) where T : FsDbEntityBase, new()
+        {
+            var msPack = new MemoryStream(bufPack);
+
+            var br = new BinaryReader(msPack);
+
+            //identity
+            coll.CurrentIdentity = br.ReadInt32();
+            //count
+            coll.InternalContainer = new List<T>(br.ReadInt32());
+            for (int i = 0; i < coll.InternalContainer.Capacity; i++)
+            {
+                var buf = br.ReadBytes(br.ReadInt32());
+                var str = Encoding.UTF8.GetString(buf);
+
+                var item = LoadEntityFromJson<T>(str);
+
+                coll.InternalContainer.Add(item);
+            }
+
+        }
+
+        //--  load/save whole
+
+        private FsDbCollection<T> LoadCollection<T>() where T : FsDbEntityBase, new()
+        {
+            var coll = new FsDbCollection<T>();
+
+            coll.EngineInstance = this;
+            coll.InternalContainer = new List<T>();
+
+            // Load data from compress
+            var compress_file_path = m_strDbFolderPath.CombineLocalPath(typeof(T).Name + COMPRESS_FILE_EX);
+            if (File.Exists(compress_file_path))
+            {
+                var bufFile = File.ReadAllBytes(compress_file_path);
+
+                var misCompress = new MemoryStream(bufFile);
+                using (var sDecompress = new GZipInputStream(misCompress))
+                {
+                    var bufArc = sDecompress.ReadToEnd();
+
+                    UnPackColl(coll, bufArc);
+                }
+            }
+
+            // load data from File System
+            var folderEntity = m_strDbFolderPath.CombineLocalPath(typeof(T).Name);
+
+            coll.UnCompressedFileCount = Directory
+                .GetFiles(folderEntity, "*" + ENTITY_FILE_EX)
+                .Select(p => File.ReadAllText(p))
+                .Select(p => LoadEntityFromJson<T>(p))
+                //  override to from compress
+                .DoEach(p => OverrodeColl<T>(coll, p))
+                //  tell filecount ~
+                .Count();
+
+            //  remove deleted 
+            coll.InternalContainer.RemoveAll(p => p.IsDeleted);
+
+            //if exist identity file, load it
+            var strFileNameIdentity = m_strDbFolderPath.CombineLocalPath(typeof(T).Name + IDENTITY_FILE_EX);
+            if (File.Exists(strFileNameIdentity))
+                coll.CurrentIdentity = TypeParser<int>.Convert((File.ReadAllText(strFileNameIdentity)));
+
+
+            return coll;
+        }
+
+        internal void Compress<T>(FsDbCollection<T> coll) where T : FsDbEntityBase, new()
+        {
+            if (coll.EngineInstance != this)
+                throw new ArgumentException("集合不属于当前引擎实例(引擎BUG?)");
+
+            if (m_OpenAsReadonly)
+                throw new InvalidOperationException("在只读打开模式尝试写入");
+
+            // compress
+
+            lock (this)
+            {
+                lock (coll)
+                {
+                    var bufArc = PackColl(coll);  //coll -> arc
+
+                    //arc -> compress
+                    var msCompress = new MemoryStream();
+                    using (var sCompress = new GZipOutputStream(msCompress))
+                    {
+                        if (MaxinumCompress)
+                            sCompress.SetLevel(9);
+
+                        sCompress.Write(bufArc, 0, bufArc.Length);
+
+                        sCompress.Flush();
+                    }
+                    var bufCompress = msCompress.ToArray();
+
+                    //write to compressed archive file
+                    var compress_file_path = m_strDbFolderPath.CombineLocalPath(typeof(T).Name + COMPRESS_FILE_EX);
+                    File.WriteAllBytes(compress_file_path, bufCompress);
+
+                    // delete all single file from File System
+                    var folder_entity = m_strDbFolderPath.CombineLocalPath(typeof(T).Name);
+                    Directory.Delete(folder_entity, true);
+
+                    //for continue add...
+                    Directory.CreateDirectory(folder_entity);
+
+                    File.Delete(m_strDbFolderPath.CombineLocalPath(typeof(T).Name + IDENTITY_FILE_EX));
+
+                    coll.UnCompressedFileCount = 0;
+                }
+            }
+        }
+
+        //--  oper
+
+        internal void UpdateIndentity<T>(int id) where T : FsDbEntityBase
+        {
+            if (m_OpenAsReadonly)
+                throw new InvalidOperationException("在只读打开模式尝试写入");
+
+            var strFileNameIdentity = m_strDbFolderPath.CombineLocalPath(typeof(T).Name + IDENTITY_FILE_EX);
+            lock (this)
+            {
+                File.WriteAllText(strFileNameIdentity, id.ToString());
+            }
+        }
+
+        internal void SaveEntity<T>(T entity) where T : FsDbEntityBase, new()
+        {
+            if (entity.ID == 0)
+                throw new ArgumentException("实体未初始化(引擎BUG?)");
+
+            if (m_OpenAsReadonly)
+                throw new InvalidOperationException("在只读打开模式尝试写入");
+
+            var coll = GetCollection<T>();
+
+            lock (this)
+            {
+                lock (coll)
+                {
+                    var json = JsonConvert.SerializeObject(entity);
+                    var folder = m_strDbFolderPath.CombineLocalPath(typeof(T).Name);
+                    var fn = folder.CombineLocalPath(entity.ID + ENTITY_FILE_EX);
+
+                    if (Directory.Exists(folder) == false)
+                        Directory.CreateDirectory(folder);
+
+                    File.WriteAllText(fn, json);
+
+                    entity.EngineInstance = this;
+
+                    coll.UnCompressedFileCount++;
+
+                    if (EnableAutoCompress && GetCollection<T>().UnCompressedFileCount > FileCountToAutoCompress)
+                    {
+                        //TODO:runtime optz, props, events
+                        var flgCompress = true;
+
+                        if (OnBeforeAutoCompress != null)
+                        {
+                            var cea = new CancelEventArgs();
+                            OnBeforeAutoCompress(GetCollection<T>(), cea);
+
+                            if (cea.Cancel)
+                                flgCompress = false;
+                        }
+
+                        if (flgCompress)
+                            GetCollection<T>().Compress();
+
+                        if (OnAfterAutoCompress != null)
+                            OnAfterAutoCompress(GetCollection<T>(), EventArgs.Empty);
+                    }
+                }
+            }
+
+        }
+
+        internal void Delete<T>(T entity) where T : FsDbEntityBase, new()
+        {
+            lock (this)
+            {
+                entity.IsDeleted = true;
+                SaveEntity(entity);
+                entity.EngineInstance = null;
+            }
+        }
+
+        //---- protects
+
+        protected virtual void OnCreate()
+        {
+            //do nothing
+        }
+
+        //---- publics
+
+        public FsDbCollection<T> GetCollection<T>() where T : FsDbEntityBase, new()
+        {
+            lock (this)
+            {
+                if (m_dicCollections.ContainsKey(typeof(T)) == false)
+                {
+                    Directory.CreateDirectory(m_strDbFolderPath.CombineLocalPath(typeof(T).Name));
+                    m_dicCollections[typeof(T)] = LoadCollection<T>();
+                }
+            }
+
+            return (FsDbCollection<T>)m_dicCollections[typeof(T)];
+        }
+
+    }
+
+
+    public class FsDbCollection<T> : ICollection<T> where T : FsDbEntityBase, new()
+    {
+        //---- internals
+
+        internal int CurrentIdentity;
+
+        internal FsDbEngine EngineInstance;
+
+        internal List<T> InternalContainer;
+
+        internal FsDbCollection()
+        {
+
+        }
+
+        public int UnCompressedFileCount { get; internal set; }
+
+        public void Compress()
+        {
+            lock (this)
+            {
+                EngineInstance.Compress(this);
+            }
+        }
+
+        //---- publics
+
+        #region ICollection<T> 成员
+
+        public void Add(T item)
+        {
+            if (item.IsDeleted)
+                throw new InvalidOperationException("实体对象已是被删除的");
+
+            lock (this)
+            {
+                lock (EngineInstance)
+                {
+                    item.ID = ++this.CurrentIdentity;
+
+                    EngineInstance.UpdateIndentity<T>(CurrentIdentity);
+                    EngineInstance.SaveEntity(item);
+
+
+                    this.InternalContainer.Add(item);
+                }
+            }
+        }
+
+        public bool Remove(T item)
+        {
+            if (item.IsDeleted)
+                throw new InvalidOperationException("实体对象已是被删除的");
+
+            if (item.EngineInstance != this.EngineInstance)
+                throw new ArgumentException("实体对象所属集合不匹配");
+
+            lock (this)
+            {
+                EngineInstance.Delete(item);
+                return InternalContainer.Remove(item);
+            }
+        }
+
+        public void Clear()
+        {
+            lock (this)
+            {
+                foreach (var item in InternalContainer)
+                    Remove(item);
+            }
+        }
+
+        public bool Contains(T item)
+        {
+            if (item.IsDeleted)
+                return false;
+
+            if (item.EngineInstance != this.EngineInstance)
+                return false;
+
+            if (item.ID == 0)
+                return false;
+
+            return InternalContainer.Contains(item);
+        }
+
+        public void CopyTo(T[] array, int arrayIndex)
+        {
+            InternalContainer.CopyTo(array, arrayIndex);
+        }
+
+        public int Count
+        {
+            get
+            {
+                return InternalContainer.Count;
+            }
+        }
+
+        public bool IsReadOnly
+        {
+            get { return false; }
+        }
+
+
+        #endregion
+
+        #region IEnumerable<T> 成员
+
+        public IEnumerator<T> GetEnumerator()
+        {
+            return InternalContainer.GetEnumerator();
+        }
+
+        #endregion
+
+        #region IEnumerable 成员
+
+        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
+        {
+            return InternalContainer.GetEnumerator();
+        }
+
+        #endregion
+
+        public void SaveChange(T item)
+        {
+            if (item.IsDeleted)
+                throw new InvalidOperationException("实体对象已是被删除的");
+
+            if (item.EngineInstance == null)
+                throw new InvalidOperationException("要保存更改,必须添加到集合");
+
+            lock (this)
+            {
+                EngineInstance.SaveEntity(item);
+            }
+        }
+
+        public void SaveOrAdd(T item)
+        {
+            if (item.EngineInstance == null)
+                Add(item);
+            else
+                SaveChange(item);
+        }
+
+    }
+
+
+    public abstract class FsDbEntityBase
+    {
+        [JsonIgnore]
+        internal FsDbEngine EngineInstance { get; set; }
+
+        public bool IsDeleted { get; internal set; }
+        public int ID { get; internal set; }
+
+        public FsDbEntityBase()
+        {
+            IsDeleted = false;
+            EngineInstance = null;
+        }
+
+    }
+
+
+    public class FsDbEntitySet<T> : IEnumerable<T> where T : FsDbEntityBase, new()
+    {
+        private FsDbEntityBase m_entity;
+        private FFunc<T, bool> m_onQuering;
+        private Action<T> m_onAdding;
+
+        public FsDbEntitySet(FsDbEntityBase entity, FFunc<T, bool> onQuering, Action<T> onAdding)
+        {
+            m_entity = entity;
+            m_onQuering = onQuering;
+            m_onAdding = onAdding;
+        }
+
+        public void Add(T entity)
+        {
+            if (m_entity.EngineInstance == null)
+                throw new InvalidOperationException("实体必须加入集合才能操作关系");
+
+            m_onAdding(entity);
+            m_entity.EngineInstance.GetCollection<T>().Add(entity);
+        }
+
+        public void AddRange(IEnumerable<T> items)
+        {
+            foreach (var item in items)
+            {
+                Add(item);
+            }
+        }
+
+        public IEnumerator<T> GetEnumerator()
+        {
+            if (m_entity.EngineInstance == null)
+                throw new InvalidOperationException("实体必须加入集合才能操作关系");
+
+            return m_entity.EngineInstance.GetCollection<T>()
+                           .Where(m_onQuering).GetEnumerator();
+        }
+
+        #region IEnumerable 成员
+
+        IEnumerator IEnumerable.GetEnumerator()
+        {
+            return GetEnumerator();
+        }
+
+        #endregion
+    }
+
+
+    public class FsDbEntityRef<T> where T : FsDbEntityBase, new()
+    {
+        private FsDbEntityBase m_OwnerEntity;
+        private FFunc<T, bool> m_onGetting;
+        private Action<T> m_onSetting;
+        private T m_Entity;
+
+        public FsDbEntityRef(FsDbEntityBase ownerEntity, FFunc<T, bool> onGetting, Action<T> onSetting)
+        {
+            m_OwnerEntity = ownerEntity;
+            m_onGetting = onGetting;
+            m_onSetting = onSetting;
+        }
+
+        public T Entity
+        {
+            get
+            {
+                if (m_OwnerEntity.EngineInstance == null)
+                    return m_Entity;
+
+                return m_OwnerEntity.EngineInstance.GetCollection<T>()
+                               .Where(m_onGetting).FirstOrDefault();
+            }
+            set
+            {
+                m_onSetting(value);
+                m_Entity = value;
+            }
+        }
+    }
+
+}

File diff suppressed because it is too large
+ 3100 - 0
FsDb/LinqBridge-1.3.cs


+ 36 - 0
FsDb/Properties/AssemblyInfo.cs

@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// 有关程序集的常规信息通过以下
+// 特性集控制。更改这些特性值可修改
+// 与程序集关联的信息。
+[assembly: AssemblyTitle("FsDb")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Microsoft")]
+[assembly: AssemblyProduct("FsDb")]
+[assembly: AssemblyCopyright("Copyright © Microsoft 2013")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// 将 ComVisible 设置为 false 使此程序集中的类型
+// 对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型,
+// 则将该类型上的 ComVisible 特性设置为 true。
+[assembly: ComVisible(false)]
+
+// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
+[assembly: Guid("5e30d25d-f99b-426b-9b2f-d38584c28ea1")]
+
+// 程序集的版本信息由下面四个值组成:
+//
+//      主版本
+//      次版本 
+//      生成号
+//      修订号
+//
+// 可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
+// 方法是按如下所示使用“*”:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

+ 135 - 0
FsDb/Utility.cs

@@ -0,0 +1,135 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using System.Linq;
+
+
+namespace FsDb
+{
+    internal static class Utility
+    {
+        public static string CombineLocalPath(this string me, params string[] nexts)
+        {
+            if (me == null || nexts.Length == 0)
+                throw new ArgumentNullException();
+
+            string dsc = Path.DirectorySeparatorChar.ToString();
+
+            var lst = nexts.ToList();// new List<string>();
+
+            lst.Insert(0, me);
+
+            return string.Join(
+                    dsc
+                    , lst.ToArray()
+                )
+            ;
+        }
+
+        public static IEnumerable<T> DoEach<T>(this IEnumerable<T> source, Action<T> actionToDo)
+        {
+            foreach (var item in source)
+            {
+                actionToDo(item);
+            }
+
+            return source;
+        }
+
+        public static byte[] ReadToEnd(this System.IO.Stream stream)
+        {
+            long originalPosition = 0;
+
+            if (stream.CanSeek)
+            {
+                originalPosition = stream.Position;
+                stream.Position = 0;
+            }
+
+            try
+            {
+                byte[] readBuffer = new byte[4096];
+
+                int totalBytesRead = 0;
+                int bytesRead;
+
+                while ((bytesRead = stream.Read(readBuffer, totalBytesRead, readBuffer.Length - totalBytesRead)) > 0)
+                {
+                    totalBytesRead += bytesRead;
+
+                    if (totalBytesRead == readBuffer.Length)
+                    {
+                        int nextByte = stream.ReadByte();
+                        if (nextByte != -1)
+                        {
+                            byte[] temp = new byte[readBuffer.Length * 2];
+                            Buffer.BlockCopy(readBuffer, 0, temp, 0, readBuffer.Length);
+                            Buffer.SetByte(temp, totalBytesRead, (byte)nextByte);
+                            readBuffer = temp;
+                            totalBytesRead++;
+                        }
+                    }
+                }
+
+                byte[] buffer = readBuffer;
+                if (readBuffer.Length != totalBytesRead)
+                {
+                    buffer = new byte[totalBytesRead];
+                    Buffer.BlockCopy(readBuffer, 0, buffer, 0, totalBytesRead);
+                }
+                return buffer;
+            }
+            finally
+            {
+                if (stream.CanSeek)
+                {
+                    stream.Position = originalPosition;
+                }
+            }
+        }
+    }
+
+    internal static class TypeParser<T> where T : struct
+    {
+        private delegate bool conv(string value, out T result);
+
+        private static readonly Type type;
+
+        private static conv del;
+
+        static TypeParser()
+        {
+            type = typeof(T);
+
+            if (type.Name == "Nullable`1")
+                throw new Exception();
+
+            var mi = type.GetMethods().First(p => p.Name == "TryParse" && p.GetParameters().Length == 2);
+            del = (conv)Delegate.CreateDelegate(typeof(conv), mi);
+        }
+
+        public static T Convert(object value)
+        {
+            if (value == null || value == DBNull.Value)
+                return default(T);
+
+            T result = default(T);
+            del(value.ToString(), out result);
+            return result;
+        }
+
+        public static T? ConvertNullable(object value)
+        {
+            if (value == null || value == DBNull.Value)
+                return null;
+
+            T result;
+            if (del(value.ToString(), out result))
+                return result;
+            return null;
+        }
+
+    }
+
+}

+ 5 - 0
FsDb/packages.config

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="Newtonsoft.Json" version="6.0.5" targetFramework="net20" />
+  <package id="SharpZipLib" version="0.86.0" targetFramework="net20" />
+</packages>