関連するテーブルからいくつかの集計情報を返す複雑なクエリを実行する必要があるコードファーストデータモデルがあります。最初に私の簡略化されたモデル:
public class Forum
{
public virtual int ForumID { get; set; }
public virtual string Name { get; set; }
public virtual ICollection<Topic> Topics { get; set; }
}
[NotMapped]
public class ForumWith : Forum
{
public virtual int topics { get; set; }
public virtual int messages { get; set; }
public virtual DateTime lastDate { get; set; }
public virtual int lastUser { get; set; }
}
public class Topic
{
public virtual int TopicID { get; set; }
public virtual string Subject { get; set; }
public virtual int ForumID { get; set; }
[ForeignKey("ForumID")]
public virtual Forum Forum { get; set; }
public virtual ICollection<Message> Messages { get; set; }
}
public class Message
{
public virtual int MessageID { get; set; }
public virtual int TopicID { get; set; }
[ForeignKey("TopicID")]
public virtual Topic Topic { get; set; }
public virtual string Text { get; set; }
public virtual DateTime CreatedDate { get; set; }
public virtual User CreatedBy { get; set; }
}
私がやりたいのは、「ForumWith」オブジェクトにトピックの数、メッセージの数、最後に作成されたメッセージの日付とユーザーを入力することです。
これを行うための私の最初の解決策は、forum.topicsおよびforum.topics.messagesコレクションに対していくつかのループを使用することでした。これは問題なく機能しますが、パフォーマンスはひどいものです。
これを修正するために、groupbyとsum/ maxの集計を使用して、3つのテーブルで左結合を実行するSQLクエリを作成しました。このSQLはcontext.Database.SqlQuery(sql);で実行されます。データは正常に入力され、パフォーマンスは非常に良好です。
私の質問は次のとおりです。
結果セットをループしてcontext.Usersから手動で入力することなく、ForumWithの「intlastUser」を実際のユーザーオブジェクト「UserlastUserObject」に置き換える方法はありますか。
パフォーマンスを維持しながら、linq / EFを介してこの種の集計を行うためのより良い方法はありますか?
SQL:
SELECT dbo.Forum.ForumID ,
dbo.Forum.Name ,
COUNT(DISTINCT dbo.Topics.TopicID) AS topics,
COUNT(DISTINCT MessageID) AS messages,
MAX(dbo.Messages.CreatedDate) AS lastDate,
(SELECT UserName FROM [User] where UserId =
CONVERT(INT,SUBSTRING(max(CONVERT(varchar,dbo.Messages.CreatedDate,20) + '#' + CONVERT(VARCHAR,dbo.Messages.CreatedBy_UserId,20)),21,10))) AS lastUser
FROM dbo.Forum
LEFT JOIN dbo.Topics ON dbo.Forum.ForumID = dbo.Topics.ForumID
LEFT JOIN dbo.Messages ON dbo.Topics.TopicID = dbo.Messages.TopicID
GROUP BY dbo.Forum.ForumID ,
dbo.Forum.Name