views:

406

answers:

0

How can for example a Blog post comment counter cache be implemented using linq2sql?

The way I currently implement this in a site I am developing is using hand coded sql queries and the ExecuteCommand() adhoc sql execution method of the linq2sql datacontext.

I would like to know if there is a better/simpler approach using linq2sql that can do the same thing.

I am really curious to find out the approach that stack overflow uses to implement counter caching using linq 2 sql. I listened to a podcast about the stack overflow site architecture which uses linq2sql and uses counter cache's to store site statistics. So maybe a developer from stack overflow can chime in.

Below is the sql query script that I use when adding a comment to a post. the query adds a comment for the post and increments the number of comments for the post in a cached column in the posts table (hence the name counter cache which is a RoR term I believe)

string addcommentquery = @"SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
        SET NOCOUNT ON
        SET XACT_ABORT ON
        DECLARE @CommentId INT
    Declare @Title nvarchar(50) set @Title = {0}
    Declare @PostId int set @PostId = {1}
    BEGIN TRANSACTION
        INSERT INTO dbo.Comments
        (
        ,Title
        ,PostId
        )
        VALUES
        (@Title
        ,@PostId
        )
        UPDATE dbo.Posts
    SET 
    CommentCount = CommentCount + 1 --atomic update-no need to get the post and then submit an update that could fail concurrency timestamp
    WHERE PostId= @PostId
    COMMIT TRANSACTION 
    SET @CommentId = SCOPE_IDENTITY() 
        SELECT @CommentId ";

//add comment to post with id=24
_dc.ExecuteQuery<int>(addcommentquery,"My 2 cents",24)

also when we remove a comment for a post we need to decrement the count in the counter cache column

string removecommentquery = @"SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
        SET NOCOUNT ON
        SET XACT_ABORT ON
Declare @CommentID int set @CommentID = {0}
Declare @PostId int set @PostId = {1}
BEGIN TRANSACTION
DELETE dbo.Comments
WHERE CommentID = @CommentID 
UPDATE dbo.Posts
CommentCount = CommentCount - 1 --atomic update
WHERE PostId= @PostId
COMMIT TRANSACTION

//remove comment with id=1 that was added to post with id=24
_dc.ExecuteNonQuery(removecommentquery,1,24)

Not sure if the approach below is how you would do this in linq 2 sql

//pseudo code
public partial class Post    
{

public void AddComment(Comment c)  
{  
    this.Comments.Add(c);
    this.commentCount = CommentCount + 1;
}

public void RemoveComment(Comment c)  
{  
    this.Comments.Remove(c);
    this.commentCount = CommentCount - 1;
}  

public void Persist()
{
    int tryCount=0;
    while(result==false && count<3)
    {
        try
        {
            tryCount++;
            _dc.SubmitChanges();
            result = true;

        }
        catch(VersionNoMatchException)
        {
            BlockForRandomMiliseconds(bound(10,100));
        }
    }  

    if(result == false)throw new RetryFailedException("max tries: " + tryCount );  

}  
}

I would really like to use linq2sql for this kind of functionality instead of hand rolling a query.

Thanks.