Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 проблема с CLR User-Defined Types  [new]
IIgor
Member

Откуда:
Сообщений: 17
При написании пользовательского типа натолкнулся на проблему.
Не могу изменять переменные с помощью описанный в классе методов.
т.е.
описав в классе переменную ps1 не могу изменить ее вызвав описанный в том же классе метод. Ошибок никаких не возникает. Но и содержание переменной не меняется.

(MSSQL2008R2, C#2010)

код тестового вызова
+

DECLARE @CObje CLRObjectTest


SET @CObje='50'
select @CObje.s1, @CObje.s2
SET @CObje.s2=N'asdf'
SET @CObje.s1=N'asdfqq'
select @CObje.s1, @CObje.s2
select @CObje.t1() --не выполняет модификацию данных
select @CObje.s1, @CObje.s2
select @CObje.t2(N'ffg') --не выполняет модификацию данных
select @CObje.s1, @CObje.s2
select @CObje.t3(N'ffg',N'ery') -- не выполняет модификацию данных
select @CObje.s1, @CObje.s2
select @CObje.t4()
select @CObje.t5(N'Test1')
select @CObje.t6(N'Test2')




Сам код CLR
+

   [Serializable]
    [SqlUserDefinedType(Format.UserDefined, IsByteOrdered = true, MaxByteSize = -1)]
    public class PageGenerate : INullable, IBinarySerialize
    {
        private string ps1;
        private string ps2;

        public string s1
        {
            get
            {
                return ps1;
            }
            set
            {
                ps1 = value;
            }
        }
        public string s2
        {
            get
            {
                return ps2;
            }
            set
            {
                ps2 = value;
            }
        }
        public int t1()
        {
            ps1 = ps1 + ps2;
            ps2 = "";
            return 1;
        }
        public int t2(SqlString sqls)
        {
            if (!sqls.IsNull)
            {
               ps2 = sqls.ToString() ;
                return 2;
            }
            else
            {
                return 1;
            }
        }
        public int t3(SqlString sqls1, SqlString sqls2)
        {
            if (!sqls1.IsNull && !sqls2.IsNull)
            {
                ps2 = sqls2.ToString();
                ps1 = sqls1.ToString();
                return 4;
            }
            if (!sqls1.IsNull && sqls2.IsNull)
            {
                ps1 = sqls1.ToString();
                return 3;
            }
            if (sqls1.IsNull && !sqls2.IsNull)
            {
                ps2 = sqls2.ToString();
                return 2;
            }
            return 1;
        }
        public SqlString t4()
        {
            return new SqlString(ps1+ps2);
        }
        public SqlString t5(SqlString sqls)
        {
            return sqls;
        }
        public SqlString t6(SqlString sqls)
        {
            return new SqlString(sqls.Value);
        }

  
        public PageGenerate()
        {
            ps1 = "clear1";
            ps2 = "clear2";
        }

        public PageGenerate(string ts)
        {
            ps1 = ts;
            ps2 = "Test";
        }

        public void Write(BinaryWriter w)
        {
            w.Write(ps1.ToString());
            w.Write(ps2.ToString());
        }
        public void Read(BinaryReader r)
        {
            ps1 = r.ReadString();
            ps2 = r.ReadString();
        }

        public static PageGenerate Null
        {
            get
            {
                return new PageGenerate();
            }
        }

        public bool IsNull
        {
            get
            {
                return (ps1 == "" ? true : false);
            }
        }

        public static PageGenerate Parse(SqlString data)
        {
            return new PageGenerate(data.ToString());
        }
        public override String ToString()
        {
            return ps1.ToString();
        }


    }

18 май 12, 17:34    [12579221]     Ответить | Цитировать Сообщить модератору
 Re: проблема с CLR User-Defined Types  [new]
aleonov
Member

Откуда:
Сообщений: 96
IIgor,

попробуй изменить private string ps1;
private string ps2;

на

public string ps1;
public string ps2;
18 май 12, 18:24    [12579591]     Ответить | Цитировать Сообщить модератору
 Re: проблема с CLR User-Defined Types  [new]
RubinDm
Member

Откуда:
Сообщений: 461
aleonov,

проверил, действительно все именно так. есть подозрение, что в случае с методами используются КОпии объекта, я почти в этом уверен. пытаюсь понять, как залогировать конструктор. если придумаешь - дай знать.
18 май 12, 19:53    [12579929]     Ответить | Цитировать Сообщить модератору
 Re: проблема с CLR User-Defined Types  [new]
RubinDm
Member

Откуда:
Сообщений: 461
RubinDm,

моя догадка подтвердилась: метод исполняется над КОПИЕЙ объекта. Под копией подразумевается новый объект, текущее состояние которого равно состоянию оригинального объекта на момент вызова метода. Метод реально вносит изменения в копию, и возвращает ожидаемый результат, но оригинальный объект остается неизменным. Строго говоря - это более чем разумно, ибо не сложно представить себе такой вот сценарий:

select T.MyClrColumn.MyMethod('SomeArg1') from MyTable T


По идее, сервер должен сделать выборку int'ов (результатов исполнения метода) и поменять состояние объектов, которые попали под выборку. Но если он это сделает, то SELECT автоматом превратится в интуитивно абсолютно непонятный UPDATE, со всеми вытекающими последствиями в виде необходимости расстановки блокировок и прочего-прочего-прочего. Понятно, что ТАК выкручивать логику движка сервера никто не разрешит, да и нет в этом необходимости.

Задача решается очень красиво и просто. Если метод реально должен менять состояние объекта, то пусть он это делает, но возвращать он должен сам измененный объект:

return this;


Если описать метод таким образом, то дальнейший план действий такой:

declare @MyClrObj MyClrType
set @MyClrObj = 'БлаБлаБла';
-- @MyClrObj будет перезаписан результатом исполнения метода // return this // THIS is MODIFIED copy of original object.
set @MyClrObj = @MyClrObj.MyMethod('Zzz');


update будет выглядеть примерно также:

update T.MyClrColumn = T.MyClrColumn.MyMethod('Zzz') from MyTable T


Дело закрыто, вердикт обжалованию не подлежит ;)
18 май 12, 20:52    [12580162]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить