Concurrency Class - Modified Date

Posts   
 
    
quentinjs avatar
quentinjs
User
Posts: 110
Joined: 09-Oct-2009
# Posted on: 29-Oct-2009 14:25:10   

I blatantly stole all of this off the internet, with minor changes from From example:[http://adriandev.blogspot.com/2007/12/optmistic-concurrency-withtimestamps.html](http://adriandev.blogspot.com/2007/12/optmistic-concurrency-withtimestamps.html)

  1. Concurrency Classes - A file to be placed in your LLBL project. EntityClass section worked for me. This factory will auto add in to all your entities. So they all need to have the same field ModifiedDate. If you have cases where you need a different Concurrency mechanism you can override it on the save.
  2. Trigger - to ensure Modified Date is updated.
  3. Example on how I used it.

1. Example Concurrency Class


using System;
using System.Collections.Generic;
using System.Linq;
using System.ComponentModel;

using System.Text.RegularExpressions;
using SD.LLBLGen.Pro.ORMSupportClasses;

using glossaryDB;
using glossaryDB.FactoryClasses;
using glossaryDB.DaoClasses;
using glossaryDB.RelationClasses;
using glossaryDB.CollectionClasses;
using glossaryDB.HelperClasses;
using glossaryDB.EntityClasses;

namespace glossaryDB.EntityClasses 
{


    /// <summary>
    /// 
    /// </summary>
    public partial class CommonEntityBase
    {

        protected override SD.LLBLGen.Pro.ORMSupportClasses.IConcurrencyPredicateFactory CreateConcurrencyPredicateFactory()
        {
            return new OptimisticConcurrencyFactory_ViaTimestampCheck();
        }

        public string ConcurrencyCheckFieldName
        {
            get { return _concurrencyCheckFieldName; }
            set { _concurrencyCheckFieldName = value; }
        }
        private string _concurrencyCheckFieldName = "ModifiedDate";

    }


    /// <summary>
    ///  
    /// </summary>
    public class OptimisticConcurrencyFactory_ViaTimestampCheck : IConcurrencyPredicateFactory
    {

        public IPredicateExpression CreatePredicate(ConcurrencyPredicateType predicateTypeToCreate, object containingEntity)
        {
            IPredicateExpression toReturn = null;
            CommonEntityBase entity = (CommonEntityBase)containingEntity;
            //EntityBase entity1 = (EntityBase)containingEntity;

            if (!string.IsNullOrEmpty(entity.ConcurrencyCheckFieldName))
            {
                toReturn = new PredicateExpression();
                IEntityField lastModifiedDateField = entity.Fields[entity.ConcurrencyCheckFieldName];
                switch (predicateTypeToCreate)
                {
                    case ConcurrencyPredicateType.Delete:
                    case ConcurrencyPredicateType.Save:
                        toReturn.Add(new FieldCompareValuePredicate(lastModifiedDateField, ComparisonOperator.Equal, lastModifiedDateField.CurrentValue)); 
                        //  Don't use DbValue -> this seems to repull this value immediately here which is different then what we need.
                        break; 

                }
            }

            return toReturn;
        }

    }

}

2. Trigger


set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
GO
ALTER TRIGGER [dbo].[tr_UserAccount_Concurrency] ON [dbo].[UserAccount] FOR INSERT, UPDATE
AS
BEGIN
UPDATE UserAccount SET ModifiedDate = getdate() 
FROM UserAccount INNER JOIN inserted ON UserAccount.UserAccount_ID = inserted.UserAccount_ID
END

3. Example Use- from my MVC app


            UserAccountEntity e_UserAccount = new UserAccountEntity();
            try
            {
                //UpdateModel(e_UserAccount);
                e_UserAccount.UpdateFrom(Request.Form);
                e_UserAccount.Save();
            }
            
            catch (ORMConcurrencyException ex)
            {
                this.ModelState.AddModelError("Exception", "Sorry, another user has already updated this User Account record");
                return this.View("edit", e_UserAccount);
            }
            return RedirectToAction("Index");


I removed all the validation wrappers etc from this to keep it clean.

MTrinder
User
Posts: 1461
Joined: 08-Oct-2008
# Posted on: 29-Oct-2009 16:46:14   

Thanks for posting this - could be useful to people.

I can suggest just one slight improvement - if you are using SQL Server (other DBs probably have equivalents) rather than using a DateTime column, use a timestamp column. This is autoincremented by the DB itself each time the record is modified, and so does away with the need for the trigger.

LLBLGen supports timestamp fields so no other changes would be needed.

Matt

quentinjs avatar
quentinjs
User
Posts: 110
Joined: 09-Oct-2009
# Posted on: 29-Oct-2009 17:07:18   

And here is a thread I just found supporting using TimeStamps.

http://www.llblgen.com/TinyForum/Messages.aspx?ThreadID=890&HighLight=1