这是我使用 ServiceStack ORMLite 进行实验的第三天。我的示例项目曾经只与 Dapper 一起工作,现在它是 Dapper 和 ServiceStack ORMLite 的混合体,两全其美。
昨晚我正在为一个 Dapper 查询而苦苦挣扎。它基本上是一个选择加入 4 个表,在 ORMLite 的代码进来之前运行良好。现在它正在一遍又一遍地失败,因为表映射到对象。它不会破坏它只是为对象分配错误的值。
我不得不继续前进,作为一个临时解决方法,我所做的是执行 4 个选择中的每一个,而不使用 Dapper 的 QueryMultiple 进行 SQL 连接,然后在 C# 上一个一个地连接结果。
请不要开始笑。我知道这当然不是最好的解决方案。然而,它仍然会去 DB 一次,但感觉并不自然。当行数增加时,这很可能是一个性能问题。
今天早上我想我找到了问题的根源:我正在使用 ORMLite 删除和创建表,并注意到字段顺序与我预期的不太一样。在 ORMLite 代码之前,我只是手动运行 SQL 脚本,所以我决定了字段的顺序。由于我的项目需要根据最终用户的需要支持 MySql、Postgresql 和 SQL Server,因此保持此类脚本的三个版本同步会很痛苦。我想用 ORMLite 自动化这个过程,当然可以利用它。
现在让我解释一下我的理论,你们专家可能会决定我是对还是错。Dapper 使用连接的查询根据命名约定将每个表的结果拆分为映射到每个类。它期望“Id”或“id”字段是表中的第一个字段。
我知道 Dapper 有一个“SplitOn”选项来处理不遵循其命名约定的表(“IdProduct”作为 PK 而不是“Id”)但在我的情况下它不能像那样使用,因为我真的没有任何控制权ORMLite 的CreateTable函数中的字段是如何排序的。它可能最终以“id”在中间,因此导致我现在遇到的同样问题。
也许查看我的代码可以为您提供更多线索。这是在 ORMLite 之前运行良好的代码:
using (var conn = this.ConnectionString.OpenDbConnection())
{
string sql = @"
select *
from insumo i
join unidadmedida um on um.id = i.idum
join lineainsumo l on l.id = i.idlinea
left outer join archivo a on a.id = i.idimagen;";
var insumos = conn.Query<Entities.Insumo, Entities.UnidadMedida,
Entities.LineaInsumo, Entities.Archivo, Entities.Insumo>(sql, (i, um, l, a)
=>
{
i.UnidadMedida = um; i.Linea = l; i.Fotografia = a ?? new Entities.Archivo();
return i;
}).ToList(); //Dapper
return insumos;
}
这是临时解决方法:
using (var conn = this.ConnectionString.OpenDbConnection())
{
string sql = @"
select * from insumo;
select * from unidadmedida;
select * from lineainsumo;
select a.*
from archivo a
join insumo i on i.idimagen = a.id;";
var q = conn.QueryMultiple(sql); //Dapper
var insumos = q.Read<Entities.Insumo>().ToList();
var ums = q.Read<Entities.UnidadMedida>().ToList();
var lineas = q.Read<Entities.LineaInsumo>().ToList();
var archivos = q.Read<Entities.Archivo>().ToList();
foreach (var i in insumos)
{
i.UnidadMedida = ums.FirstOrDefault(c => c.Id == i.IdUm);
i.Linea = lineas.FirstOrDefault(c => c.Id == i.IdLinea);
i.Fotografia = archivos.FirstOrDefault(c => c.Id == i.IdImagen) ?? new Entities.Archivo();
}
return insumos;
}
我正在研究 ORMLite 的代码,似乎ToCreateTableStatement函数可能是为了解决我的问题而修改的地方。也许在我的类定义中为每个字段添加一个属性来说明所需的字段创建顺序是否可行?
我正在考虑将其添加到FieldDefinition代码中:
public bool FirstField { get; set; }
并添加一个属性来装饰 C# 字段,如下所示:
[Alias("name")]
public string Name { get; set; }
[Alias("id")]
[PrimaryKey]
[FirstField(true)]
public int Id { get; set; }
然后在创建字段时,代码可以遵循此类属性的值,并允许控制最终字段在表格中的位置。
如果我走在正确的轨道上,请告诉我,或者,也许还有另一种比这个更优雅的选择。
提前致谢。