switch to sqlite

This commit is contained in:
2022-03-11 16:10:11 +08:00
parent f5f16d43f4
commit 5ec4119025
25 changed files with 286 additions and 435 deletions

View File

@ -1,9 +1,12 @@
using System.Xml.Linq;
using SQLite;
namespace Billing.Models
{
public class Account : BaseModel
public class Account : IIdItem
{
private const string ICON_DEFAULT = "ic_default";
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public string Icon { get; set; } = ICON_DEFAULT;
public AccountCategory Category { get; set; }
@ -11,28 +14,6 @@ namespace Billing.Models
public decimal Initial { get; set; }
public decimal Balance { get; set; }
public string Memo { get; set; }
public override void OnXmlDeserialize(XElement node)
{
Id = Read(node, nameof(Id), 0);
Icon = Read(node, nameof(Icon), ICON_DEFAULT);
Category = (AccountCategory)Read(node, nameof(Category), 0);
Name = Read(node, nameof(Name), string.Empty);
Initial = Read(node, nameof(Initial), 0m);
Balance = Read(node, nameof(Balance), 0m);
Memo = Read(node, nameof(Memo), null);
}
public override void OnXmlSerialize(XElement node)
{
Write(node, nameof(Id), Id);
Write(node, nameof(Icon), Icon);
Write(node, nameof(Category), (int)Category);
Write(node, nameof(Name), Name);
Write(node, nameof(Initial), Initial);
Write(node, nameof(Balance), Balance);
Write(node, nameof(Memo), Memo);
}
}
public enum AccountCategory

View File

@ -1,186 +0,0 @@
using System;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml.Linq;
namespace Billing.Models
{
public interface IModel
{
void OnXmlSerialize(XElement node);
void OnXmlDeserialize(XElement node);
}
public abstract class BaseModel : IModel, IDisposable
{
public const string ICON_DEFAULT = "ic_default";
private bool disposed = false;
public static T ParseXml<T>(string xml) where T : BaseModel, new()
{
XDocument doc = XDocument.Parse(xml);
T model = new();
model.OnXmlDeserialize(doc.Root);
return model;
}
protected static string ToString(IFormattable v) => v.ToString(null, CultureInfo.InvariantCulture);
protected static double ParseDouble(string s) => double.Parse(s, CultureInfo.InvariantCulture);
protected static decimal ParseDecimal(string s) => decimal.Parse(s, CultureInfo.InvariantCulture);
protected static int ParseInt(string s) => int.Parse(s, CultureInfo.InvariantCulture);
protected static long ParseLong(string s) => long.Parse(s, CultureInfo.InvariantCulture);
protected static bool IsTrue(string s) =>
string.Equals(s, "true", StringComparison.OrdinalIgnoreCase) ||
string.Equals(s, "yes", StringComparison.OrdinalIgnoreCase) ||
s == "1";
#region Private Methods
private static XElement WriteString(XElement parent, string name, string val, Action<XElement> action = null)
{
XElement ele;
if (val == null)
{
ele = new XElement(name);
}
else
{
ele = new XElement(name, val);
}
action?.Invoke(ele);
parent.Add(ele);
return ele;
}
private static T ReadSubnode<T>(XElement node, string subname, Func<XElement, T> func)
{
var ele = node.Elements().FirstOrDefault(e => string.Equals(e.Name.ToString(), subname, StringComparison.OrdinalIgnoreCase));
return func(ele);
}
private static T ReadObject<T>(XElement node) where T : IModel, new()
{
if (IsTrue(node.Attribute("null")?.Value))
{
return default;
}
T value = new();
value.OnXmlDeserialize(node);
return value;
}
private static T[] ReadArray<T>(XElement node) where T : IModel, new()
{
if (IsTrue(node.Attribute("null")?.Value))
{
return default;
}
int count = ParseInt(node.Attribute("count").Value);
T[] array = new T[count];
foreach (XElement ele in node.Elements("item"))
{
int index = ParseInt(ele.Attribute("index").Value);
array[index] = ReadObject<T>(ele);
}
return array;
}
#endregion
#region Read/Write Helper
protected static XElement Write(XElement parent, string name, string val) => WriteString(parent, name, val);
protected static XElement Write(XElement parent, string name, DateTime date) => WriteString(parent, name, ToString(date.Ticks));
protected static XElement Write<T>(XElement parent, string name, T value) where T : IFormattable => WriteString(parent, name, ToString(value));
protected static XElement WriteObject<T>(XElement parent, string name, T value) where T : IModel => WriteString(parent, name, null,
action: ele =>
{
if (value == null)
{
ele.Add(new XAttribute("null", 1));
}
else
{
value.OnXmlSerialize(ele);
}
});
protected static XElement WriteArray<T>(XElement parent, string name, T[] value) where T : IModel => WriteString(parent, name, null,
action: ele =>
{
if (value == null)
{
ele.Add(new XAttribute("null", 1));
}
else
{
ele.Add(new XAttribute("count", value.Length));
for (var i = 0; i < value.Length; i++)
{
XElement item = WriteObject(ele, "item", value[i]);
item.Add(new XAttribute("index", i));
}
}
});
protected static string Read(XElement node, string subname, string def) => ReadSubnode(node, subname, e => e?.Value ?? def);
protected static int Read(XElement node, string subname, int def) => ReadSubnode(node, subname, e => e == null ? def : ParseInt(e.Value));
protected static long Read(XElement node, string subname, long def) => ReadSubnode(node, subname, e => e == null ? def : ParseLong(e.Value));
protected static double Read(XElement node, string subname, double def) => ReadSubnode(node, subname, e => e == null ? def : ParseDouble(e.Value));
protected static decimal Read(XElement node, string subname, decimal def) => ReadSubnode(node, subname, e => e == null ? def : ParseDecimal(e.Value));
protected static DateTime Read(XElement node, string subname, DateTime def) => ReadSubnode(node, subname, e => e == null ? def : new DateTime(ParseLong(e.Value)));
protected static T ReadObject<T>(XElement node, string subname, T def = default) where T : IModel, new() => ReadSubnode(node, subname, e => e == null ? def : ReadObject<T>(e));
protected static T[] ReadArray<T>(XElement node, string subname, T[] def = null) where T : IModel, new() => ReadSubnode(node, subname, e => e == null ? def : ReadArray<T>(e));
#endregion
public XDocument ToXml()
{
XDocument xdoc = new(new XDeclaration("1.0", "utf-8", "yes"), new XElement("root"));
ToXml(xdoc.Root);
return xdoc;
}
public void ToXml(XElement node)
{
OnXmlSerialize(node);
}
public void SaveToStream(Stream stream)
{
ToXml().Save(stream, SaveOptions.DisableFormatting);
}
public abstract void OnXmlSerialize(XElement node);
public abstract void OnXmlDeserialize(XElement node);
public override string ToString()
{
using MemoryStream ms = new();
//using StreamWriter writer = new(ms, Encoding.UTF8);
//XDocument xdoc = ToXml();
//xdoc.Save(writer, SaveOptions.DisableFormatting);
//writer.Flush();
SaveToStream(ms);
ms.Seek(0, SeekOrigin.Begin);
using StreamReader reader = new(ms, Encoding.UTF8);
return reader.ReadToEnd();
}
protected virtual void Dispose(bool dispose) { }
public void Dispose()
{
if (!disposed)
{
Dispose(true);
disposed = true;
}
}
}
}

View File

@ -1,10 +1,11 @@
using System;
using System.Xml.Linq;
using SQLite;
namespace Billing.Models
{
public class Bill : BaseModel
public class Bill : IIdItem
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public decimal Amount { get; set; }
public string Name { get; set; }
@ -13,29 +14,5 @@ namespace Billing.Models
public string Store { get; set; }
public DateTime CreateTime { get; set; }
public string Note { get; set; }
public override void OnXmlDeserialize(XElement node)
{
Id = Read(node, nameof(Id), 0);
Amount = Read(node, nameof(Amount), 0m);
Name = Read(node, nameof(Name), string.Empty);
CategoryId = Read(node, nameof(CategoryId), -1);
WalletId = Read(node, nameof(WalletId), -1);
Store = Read(node, nameof(Store), string.Empty);
CreateTime = Read(node, nameof(CreateTime), default(DateTime));
Note = Read(node, nameof(Note), string.Empty);
}
public override void OnXmlSerialize(XElement node)
{
Write(node, nameof(Id), Id);
Write(node, nameof(Amount), Amount);
Write(node, nameof(Name), Name);
Write(node, nameof(CategoryId), CategoryId);
Write(node, nameof(WalletId), WalletId);
Write(node, nameof(Store), Store);
Write(node, nameof(CreateTime), CreateTime);
Write(node, nameof(Note), Note);
}
}
}

View File

@ -1,50 +1,19 @@
using Xamarin.Forms;
using System.Xml.Linq;
using SQLite;
namespace Billing.Models
{
public class Category : BaseModel
public class Category : IIdItem
{
private const string ICON_DEFAULT = "ic_default";
private const long TRANSPARENT_COLOR = 0x00ffffffL;
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public CategoryType Type { get; set; }
public string Icon { get; set; } = ICON_DEFAULT;
public string Name { get; set; }
public Color TintColor { get; set; } = Color.Transparent;
public long TintColor { get; set; } = TRANSPARENT_COLOR;
public int? ParentId { get; set; }
public override void OnXmlDeserialize(XElement node)
{
Id = Read(node, nameof(Id), 0);
Type = (CategoryType)Read(node, nameof(Type), 0);
Icon = Read(node, nameof(Icon), ICON_DEFAULT);
Name = Read(node, nameof(Name), string.Empty);
var color = Read(node, nameof(TintColor), string.Empty);
if (!string.IsNullOrEmpty(color))
{
TintColor = Color.FromHex(color);
}
var parentId = Read(node, nameof(ParentId), -1);
if (parentId >= 0)
{
ParentId = parentId;
}
}
public override void OnXmlSerialize(XElement node)
{
Write(node, nameof(Id), Id);
Write(node, nameof(Type), (int)Type);
Write(node, nameof(Icon), Icon);
Write(node, nameof(Name), Name);
if (TintColor != Color.Transparent)
{
Write(node, nameof(TintColor), TintColor.ToHex());
}
if (ParentId != null)
{
Write(node, nameof(ParentId), ParentId.Value);
}
}
}
public enum CategoryType

View File

@ -0,0 +1,7 @@
namespace Billing.Models
{
public interface IIdItem
{
public int Id { get; }
}
}