Разработка
28
Окт
4

Счетчик, эпизод II

Использование SQL Server’а для создания счетчиков – простой и надежный способ создания уникальной нумерации каких-либо сущностей. В связи с чем мы сейчас его и рассмотрим…

Процедура генерации счетчика будет такой:

  • Когда пользователь создает новую запись, срабатывает плагин зарегистрированный на pre-create или post-create события;
  • Сначала плагин проверяет, что задействован нужный объект;
  • Затем плагин вызывает хранимую процедуру, которая приращает счетчик в специально созданной для этого таблице. Если плагин был зарегистрирован на событие post-create, в счетчике может быть использован GUID созданной записи;
  • Хранимая процедура возвращает приращенный счетчик в плагин;
  • Ну и на последок, плагин записывает значение счетчика в создаваемую запись.

Итак…

  • Создайте новое текстовое поле в объекте Бизнес-партнер с именем new_counter – в нем будет храниться значение счетчика. Вынесите его на форму и заблокируйте;


  • Выполните в SQL Server Management Studio в отношении БД организации CRM такой SQL-код:
    CREATE TABLE Counter (
    	Name nvarchar(128) NOT NULL,
    	CounterNum Int NOT NULL
    )
    GO
    

    Этот код создает таблицу, в которой и будут храниться счетчики в таком виде:

    Имя счетчика Значение счетчика
    Счетчик1 4
    Счетчик2 45
    Счетчик3 12
    Счетчик4 11
  • Далее выполните еще один SQL-запрос:
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    
    CREATE procedure [dbo].[GenerateUniqueNum](
    	@counterName nvarchar(128), -- Имя счетчика
    	@startValue int = 1 -- Стартовое значение счетчика по умолчанию
    )
    AS
    BEGIN
    	set nocount on
    	
    	Declare @CurrentNum int
    	-- Получаем текущее значение счетчика
    	SELECT @CurrentNum = (SELECT TOP 1 CounterNum from Counter where Name = @counterName)
    	
    	if (@CurrentNum >= 1) -- Если счетчик существует, то
    		begin
    			UPDATE Counter -- Обновляем его
    			SET CounterNum = @CurrentNum + 1
    			WHERE Name = @counterName
    		end
    	ELSE
    		begin
    			INSERT Counter ( -- Иначе создаем новый
    				Name,
    				CounterNum
    			) VALUES (
    				@counterName,
    				@StartValue
    			)
    		end
    
    	SELECT -- Возвращаем приращенное значение счетчика
    		CounterNum
    	FROM
    		Counter
    	WHERE
    		Name = @counterName
    END
    GO
    

    Этот код создает в SQL Server’е хранимую процедуру, которая делает следующее:

    • На входе принимает два параметра: имя счетчика (обязательный параметр) и начальное значение счетчика (необязательный параметр, используется при создании нового счетчика; если его не задать при создании счетчика, то по-умолчанию равен 1);
    • Затем получаем текущее значение счетчика, имя которого передано в качестве параметра;
    • Если счетчик существует, то обновляем его значение на единицу. Если не существует, то создаем его (либо с начальным значением 1, либо с начальным значением переданным в качестве параметра);
    • Возвращаем значение счетчика, имя которого передано в качестве параметра.


  • Создайте новый плагин, подключите к нему сборки SDK (Microsoft.Crm.Sdk.dll и Microsoft.Crm.SdkTypeProxy.dll) и добавьте ссылку на System.Web.Services. Подпишите плагин;
  • Поместите в плагин такой код:
    using System;
    using System.Collections.Generic;
    using System.Text;
    using Microsoft.Crm.Sdk;
    using Microsoft.Crm.SdkTypeProxy;
    using System.Data;
    using System.Data.SqlTypes;
    using System.Data.SqlClient;
    using System.Web.Services;
    
    namespace ClassLibrary1
    {
        public class Class1: IPlugin
        {
            // Получаем из конфигурационных данных шага плагина имя счетчика
            string sUnsecure;
            public Class1(string unsecure)
            {
                sUnsecure = unsecure;
            }
            
            public void Execute(IPluginExecutionContext context)
            {
                DynamicEntity entity = null;
    
                // Проверяем, что плагин сработал для объекта Бизнес-партнер
                if (context.InputParameters.Properties.Contains("Target") &&
                   context.InputParameters.Properties["Target"] is DynamicEntity)
                {
                    entity = (DynamicEntity)context.InputParameters.Properties["Target"];
                    if (entity.Name != EntityName.account.ToString()) { return; }
                }
                else
                {
                    return;
                }
    
                try
                {
                    int sequentialId = 0;
    
                    // Подключаемся к SQL серверу
                    SqlConnection conn = new SqlConnection("Data Source=win-n22hj23d1b1;Initial Catalog=superfirma_MSCRM;Integrated Security=sspi");
                    // Вызываем хранимую процедуру
                    SqlCommand cmd = new SqlCommand("[GenerateUniqueNum]", conn);
                    cmd.CommandType = CommandType.StoredProcedure;
                    cmd.Parameters.AddWithValue("@counterName", sUnsecure);
                    conn.Open();
                    sequentialId = (int)cmd.ExecuteScalar(); // Получаем значение счетчика
                    conn.Close();
    
                    // Добавляем к DynamicEntity поле new_counter, содержащее значение счетчика.
                    StringProperty createCounetr = new StringProperty("new_counter", sequentialId.ToString());
                    entity.Properties.Add(createCounetr);
                    return;
    
                }
                catch (System.Web.Services.Protocols.SoapException ex)
                {
                    throw new InvalidPluginExecutionException("Ошибка: ", ex);
                }
            }
        }
    }
    

    В коде происходит следующее:

    • Для начала мы получаем из настроек шага плагина имя счетчика, который в данном случае нам необходимо задействовать;
    • Проверяем, что плани вызван для объекта Бизнес-партнер;
    • Далее подключаемся к SQL Server’у (не забудьте поменять параметры подключения на свои);
    • Вызываем хранимую процедуру и передаем ей в качестве параметра имя счетчика;
    • Получаем из хранимой процедуры приращенное значение счетчика;
    • Подставляем значение счетчика в создаваемую запись.
  • Скомпилируйте плагин и зарегистрируйте в CRM с помощью Plugin Registration Tool;
  • Для плагина создайте шаг на событие Create, объект Account и стадию Pre. А в Unsecure Configuration поместите любое имя счетчика, которое будет использоваться для этого объекта;


  • Ну и тестируем… просто создайте новую запись Бизнес-партнера 🙂


Комментарии (4)
  • logger 28.10.2010

    Добрый вечер!
    Простите великодушно, что не по теме, но вышел 13-ый пакет обновлений 🙂
    http://www.microsoft.com/downloads/details.aspx?familyid=406E6247-873B-4DB0-8A25-3F041B066844&displaylang=ru

  • slivka_83 28.10.2010

    Уфф… знаю 🙂 тока все нет времени поместить его в ларчик..

    Здрасте 🙂

  • Паша 28.10.2010

    На .Net пишу давно. Можете подобъяснить код, пожалуйста?

    Именно непонятен момент где вы подключаетесь к SQL, получаете значение счётчика, завершаетее сессию и укладываете полученное значение в Target. Вся эта конструкция — внутри try…catch и стоит обработка SoapException. Но в этом коде нигде не может такое исключение возникнуть… Может опечатались и это SQLException?

  • slivka_83 28.10.2010

    Да скорее не опечатался, а просто не обратил внимание… скопипастил из другого кода 🙂 мне то самому по барабану на этот Exception, т.к. речь не о нем 🙂 и у меня на тестовой среде Exception’ов нет (после доведения до ума) 🙂

*

code