LINQ オプション.loadwith の問題
-
22-08-2019 - |
質問
私はタグベースの ASP.net システムを作成しています。次の db スキームを使用します。
Topic <many-many> TagTopicMap <many-many> Tag
基本的に、これは私が以下から見つけた 3NF アプローチ (toxi) です。 http://www.pui.ch/phred/archives/2005/04/tags-database-schemas.html
私が持っているコードスニペットは次のとおりです。
DataLoadOptions options = new DataLoadOptions();
options.LoadWith<Topic>(t => t.TagTopicMaps);
options.LoadWith<TagTopicMap>(tt => tt.Tag);
var db = new lcDbDataContext();
db.LoadOptions = options;
db.Log = w;
var x = from topic in db.Topics
orderby topic.dateAdded descending
select topic;
ViewData["TopicList"] = x.Take(10);
これを実行すると、結果は問題ありませんが、11 個の単一 SQL クエリが表示されます。そのうちの 1 つは、上位 10 トピックのリストを取得するためのものです。
SELECT TOP (10) [t0].[Id], [t0].[title], [t0].[dateAdded]
FROM [dbo].[Topics] AS [t0] ORDER BY [t0].[dateAdded] DESC
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.30729.1
残りの 10 個はタグの詳細を個別に取得するためのものです。
2 つのloadwith ステートメントのオンとオフを切り替えようとしたところ、次のようなことが起こることがわかりました。
loadwith<topic> : no difference for on or off.
loadwith<tagtopicmap>: 11 Queries when on, much more when off.
つまり、2 番目のloadwith オプションのみが期待どおりに機能します。最初のものは効果がありません!
結果セット ToList() も作成してみました。しかし、さらに問題も出てきます。タグの詳細部分では、それらのユニークなアイテムのみが取得され、それらの繰り返しタグ (もちろん、同じタグが多数のトピックに出現する可能性があります!) はすべてクエリによって削除されます。
最後に、以下はデータを取得するために aspx で使用したコードです。結果を tolist() にする場合は、(IQueryable) を (IList) に変更します。
<% foreach (var t in (IQueryable)ViewData["TopicList"])
{
var topic = (Topic)t;
%>
<li>
<%=topic.title %> ||
<% foreach (var tt in (topic.TagTopicMaps))
{ %>
<%=tt.Tag.Name%>,
<%} %>
</li>
<%
}
%>
解決
短い答えは次のとおりです。LinqToSql にはこのような問題がいくつかあり、場合によっては回避策を使用する必要があります。
Linq2Sql LoadWith オプションは単にデータベース テーブル間の内部結合を引き起こすだけなので、Linq ステートメントを次のように書き直すことで同様の動作を強制できます (タイプミスはご容赦ください。私は VB 構文で Linq を書くことに慣れています...)。
var x = from topic in db.Topics
join topicMap in topic.TagTopicMaps
orderby topic.dateAdded descending
group topicMap by topicMap.topic into tags = Group;
この構文はひどく間違っている可能性がありますが、基本的な考え方は、Linq2Sql に Topics と TagTopicMaps の間の結合を評価させ、その後、グループ化 (または「グループ結合」、「let」など) を使用してオブジェクト階層を保持するというものです。結果セット。
他のヒント
datacontext クラスの EnabledDefferedLoad を false に設定します。
あなたの場合の問題は Take(10) です。以下は馬の口からです。
推奨される回避策は、Skip(0) を追加することです。私にとってはうまくいきませんでしたが、Skip(1) はうまくいきました。役に立たないかもしれませんが、少なくとも私は自分の問題がどこにあるのかを知っています。