ServiceStackORMLiteで実験を行うのはこれで3日目です。以前はDapperでのみ機能していた私のサンプルプロジェクトは、現在はDapperとServiceStack ORMLiteの両方を組み合わせており、両方の長所を活用しています。
昨夜、私はDapperクエリで苦労していました。これは基本的に、ORMLiteのコードが入る前に正常に実行されていた4つのテーブルを結合する選択です。現在、オブジェクトに対するテーブルマッピングのために何度もフェイルオーバーしています。壊れることはなく、オブジェクトに間違った値を割り当てるだけです。
一時的な回避策として、DapperのQueryMultipleを使用してSQL結合なしで4つの選択のそれぞれを実行し、その後、C#で結果を1つずつ結合するように進めなければなりませんでした。
笑い始めないでください。もちろん、これが最善の解決策ではないことを私は知っています。それでも、DBに1回アクセスすることはできますが、自然な感じではありません。行数が増えると、パフォーマンスの問題になる可能性があります。
今朝、問題の原因を見つけたと思います。ORMLiteを使用してテーブルを削除して作成しているところ、フィールドの順序が期待どおりではないことに気付きました。ORMLiteコードの前は、SQLスクリプトを手動で実行しただけなので、フィールドの順序を決定しました。私のプロジェクトは、最終ユーザーが望むようにMySql、Postgresql、およびSQL Serverをサポートする必要があるため、このようなスクリプトの3つのバージョンを同期させるのは面倒です。このプロセスをORMLiteで自動化し、もちろんそれを活用したいと思います。
さて、私の理論を説明しましょう。あなたの専門家は、私が正しいか間違っているかを決めるかもしれません。結合を使用したDapperのクエリは、命名規則に基づいて、各テーブルの結果を分割して各クラスにマップします。「Id」または「id」フィールドがテーブルの最初のフィールドであることが期待されます。
Dapperには、命名規則に従わないテーブルを処理するための「SplitOn」オプションがあることは知っていますが(「Id」ではなく「IdProduct」をPKとして)、私の場合、実際には制御できないため、そのように使用することはできません。 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; }
次に、フィールドを作成するときに、コードはそのようなプロパティの値に従い、テーブル上の最終的なフィールドの位置を制御できるようにします。
私が正しい方向に進んでいるかどうか、またはこれよりもエレガントな別の方法があるかどうかを教えてください。
前もって感謝します。