1

我有大量使用 protobuf-csharp-port 生成的 C# 类。我最终为他们创建了自己的简单 ORM 机制。

原来 OrmLite 正是我想要的。但我现在“卡住”了 protobuf 类。最大的问题是,对于每个实体,我有两个类:EntityClass(只读)和 EntityClass.Builder。

有没有办法集成 OrmLite 和 protobuf-csharp-port 类(及其构建器)?

4

1 回答 1

1

我设法使它像这样工作:

我为 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));
        }
    }
}
于 2015-07-29T20:17:22.570 回答