BITKit/Src/LiteDb/LiteDbDictionary.cs

158 lines
4.7 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using LiteDB;
namespace Net.BITKit.Database
{
public class LiteDbDictionary<TKey, TValue> : IDictionary<TKey, TValue>, IDisposable where TKey : notnull
{
// 内部的 LiteDB 数据库实例
private readonly LiteDatabase _db;
// LiteDB 集合名称可以自定义,默认为 "kv"
private readonly ILiteCollection<KeyValueItem> _collection;
// 内部使用的键值项POCO类
private class KeyValueItem
{
// LiteDB 将此字段作为文档的 _id主键
[BsonId] public TKey Key { get; set; }
public TValue Value { get; set; }
}
public LiteDbDictionary()
{
_db = new LiteDatabase(":memory:");
_collection = _db.GetCollection<KeyValueItem>(typeof(TValue).Name);
_collection.EnsureIndex(x => x.Key);
}
/// <summary>
/// 构造函数
/// connectionString 可以是磁盘文件(如 "Filename=MyData.db;Mode=Shared"
/// 或内存数据库(如 ":memory:"
/// </summary>
/// <param name="connectionString">数据库连接字符串</param>
/// <param name="collectionName">集合名称,默认 "kv"</param>
public LiteDbDictionary(string connectionString, string collectionName = "kv")
{
_db = new LiteDatabase(connectionString);
_collection = _db.GetCollection<KeyValueItem>(collectionName);
// 确保对键生成索引
_collection.EnsureIndex(x => x.Key);
}
#region IDictionary
public TValue this[TKey key]
{
get
{
var bsonId = _db.Mapper.Serialize(typeof(TKey), key);
var item = _collection.FindById(bsonId);
if (item == null) throw new KeyNotFoundException($"Key '{key}' not found.");
return item.Value;
}
set
{
var item = new KeyValueItem { Key = key, Value = value };
_collection.Upsert(item);
}
}
public ICollection<TKey> Keys => _collection.FindAll().Select(x => x.Key).ToList();
public ICollection<TValue> Values => _collection.FindAll().Select(x => x.Value).ToList();
public int Count => _collection.Count();
public bool IsReadOnly => false;
public void Add(TKey key, TValue value)
{
if (ContainsKey(key))
throw new ArgumentException($"An element with the key '{key}' already exists.");
_collection.Insert(new KeyValueItem { Key = key, Value = value });
}
public bool ContainsKey(TKey key)
{
return _collection.Exists(x => x.Key.Equals(key));
}
public bool Remove(TKey key)
{
var bsonKey = _db.Mapper.Serialize(typeof(TKey), key);
return _collection.Delete(bsonKey);
}
public bool TryGetValue(TKey key, out TValue value)
{
var bsonKey = _db.Mapper.Serialize(typeof(TKey), key);
var doc = _collection.FindById(bsonKey);
if (doc == null)
{
value = default;
return false;
}
value = doc.Value;
return true;
}
public void Add(KeyValuePair<TKey, TValue> item)
{
Add(item.Key, item.Value);
}
public void Clear()
{
_collection.DeleteAll();
}
public bool Contains(KeyValuePair<TKey, TValue> item)
{
if (TryGetValue(item.Key, out var val))
return EqualityComparer<TValue>.Default.Equals(val, item.Value);
return false;
}
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
{
foreach (var kv in this)
{
array[arrayIndex++] = kv;
}
}
public bool Remove(KeyValuePair<TKey, TValue> item)
{
if (Contains(item))
return Remove(item.Key);
return false;
}
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
foreach (var item in _collection.FindAll())
{
yield return new KeyValuePair<TKey, TValue>(item.Key, item.Value);
}
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
#endregion
#region IDisposable
public void Dispose()
{
_db?.Dispose();
}
#endregion
}
}