我有大量使用 protobuf-csharp-port 生成的 C# 类。我最终为他们创建了自己的简单 ORM 机制。
原来 OrmLite 正是我想要的。但我现在“卡住”了 protobuf 类。最大的问题是,对于每个实体,我有两个类:EntityClass(只读)和 EntityClass.Builder。
有没有办法集成 OrmLite 和 protobuf-csharp-port 类(及其构建器)?
我有大量使用 protobuf-csharp-port 生成的 C# 类。我最终为他们创建了自己的简单 ORM 机制。
原来 OrmLite 正是我想要的。但我现在“卡住”了 protobuf 类。最大的问题是,对于每个实体,我有两个类:EntityClass(只读)和 EntityClass.Builder。
有没有办法集成 OrmLite 和 protobuf-csharp-port 类(及其构建器)?
我设法使它像这样工作:
我为 IDbConnection 创建了一个 InitProtoTable 扩展,在程序的一开始就需要为每个原型调用它,例如:
var dbFactory = new OrmLiteConnectionFactory(...);
var db = dbFactory.Open();
db.InitProtoTable<Person.Builder>();
之后,可以调用 OrmLite 方法:
db.DropTable<Person.Builder>();
db.CreateTable<Person.Builder>();
扩展看起来像这样:
public static class OrmLiteExtensions
{
public static void InitProtoTable<B>(this IDbConnection db)
where B : IBuilder, new()
{
var desc = new B().DescriptorForType;
var model = ModelDefinition<B>.Definition;
model.Name = desc.Name;
model.IgnoredFieldDefinitions.Clear();
var fieldList = new List<FieldDefinition>();
var fieldMap = desc.Fields
.ToDictionary(f => f.Name, StringComparer.OrdinalIgnoreCase);
foreach (var field in model.FieldDefinitions)
{
if (fieldMap.ContainsKey(field.Name)) fieldList.Add(field);
}
model.FieldDefinitions = fieldList;
model.AfterInit();
if (db.TableExists<B>())
{
var columns = GetColumnNames<B>(db, model.ModelName);
var missing = model.FieldDefinitions
.Where(field => !columns.Contains(field.FieldName));
foreach (var field in missing)
{
field.DefaultValue = fieldMap[field.Name].DefaultValue.ToString();
db.AddColumn(typeof(B), field);
Console.WriteLine(db.GetLastSql());
}
}
}
private static HashSet<string> GetColumnNames<T>(IDbConnection db, string tableName)
{
using (var cmd = db.CreateCommand())
{
// Workaround to RDMS agnostic table column names discovery.
cmd.CommandText = string.Format("SELECT * FROM {0} WHERE 1!=1", tableName);
var table = new DataTable();
table.Load(cmd.ExecuteReader());
return new HashSet<string>(
table.Columns.OfType<DataColumn>().Select(c => c.ColumnName));
}
}
}