Страницы

Поиск по вопросам

Показаны сообщения с ярлыком cursor. Показать все сообщения
Показаны сообщения с ярлыком cursor. Показать все сообщения

четверг, 9 апреля 2020 г.

Как узнать позицию курсора мыши относительно экрана?

#c_sharp #wpf #position #cursor

                    
Как узнать позицию курсора по координатам (X, Y) относительно экрана, не прибегая
к средствам Windows.Forms?
    


Ответы

Ответ 1



В WPF есть класс Mouse у которого есть метод GetPosition. Чтобы получить позицию курсора относительно экрана можно использовать метод PointToScreen private void MainWindow_OnMouseMove(object sender, MouseEventArgs e) { var windowPosition = Mouse.GetPosition(this); var screenPosition = this.PointToScreen(windowPosition); this.Title = string.Format("{0} --- {1}", windowPosition, screenPosition); } Или как еще один вариант - использовать PInvoke.

пятница, 13 марта 2020 г.

SQL, cursor, перебор, добавляется две записи вместо одной

#sql_server #циклы #cursor


Пытаюсь с помощью курсора перебрать исходные данные и для каждой записи сделать те
или иные изменения. Вот сам запрос:

DECLARE @ID bigint --id attachments
DECLARE @personID BIGINT
DECLARE @territoryServiceID BIGINT
DECLARE @isAtClosed BIT

DECLARE @currentServerDate DATETIME = '2016-01-01 01:10:00.000' --this change GETDATE()
DECLARE @BeginDate DATETIME SET @BeginDate = @currentServerDate
DECLARE @periodYear INT SET @periodYear = DATEPART(YEAR,@currentServerDate) - 1

DECLARE cur cursor LOCAL STATIC
FOR
SELECT at.id, at.personID, at.territoryServiceID, ts.isClosing
FROM Attachments at
INNER JOIN Person p ON p.id = at.personID AND p.parentID IS NULL
INNER JOIN TerritoryServices ts ON ts.id = at.territoryServiceID
LEFT JOIN Attachments at2 ON at2.personID = at.personID AND at2.parentID = at.id
AND at2.attachmentStatusID IN (2,11,12)
WHERE at.attachmentStatusID = 1 AND at.causeOfAttachID = 8 AND at.endDate IS NOT NULL
AND at2.id IS NULL
AND p.id IN (15300000019296419,15300000018501113,15300000014988209,414674754,420940229,409531785)


OPEN cur

FETCH NEXT FROM cur INTO @ID, @personID, @territoryServiceID, @isAtClosed
WHILE @@FETCH_STATUS = 0
BEGIN
DECLARE @personID_NVARCHAR NVARCHAR(MAX) SET @personID_NVARCHAR = CONVERT(NVARCHAR(MAX),@personID)
PRINT '1 ('+@personID_NVARCHAR+')'

IF (@isAtClosed = 1) -- if ter of CA is closing
    BEGIN
        -- Insert error into ErrorHandlingCampainOfAttach
        DECLARE @ErrorDescr NVARCHAR(MAX) SET @ErrorDescr = 'TerId: ' + CONVERT(NVARCHAR(MAX),@territoryServiceID)
        INSERT INTO [dbo].[ErrorHandlingCampainOfAttach] ([AttachmentsID],[personID],[territoryServiceID],[periodYear],[reasonError],[addDate],[description])
        VALUES (@ID, @personID, @territoryServiceID, @periodYear, 1, GETDATE(), @ErrorDescr)
    END
ELSE
    BEGIN
        DECLARE @terAt2ID BIGINT
        DECLARE @isAt2Close BIT = 0
        SELECT @isAt2Close = ts.isClosing, @terAt2ID = ts.id FROM Attachments at 
        INNER JOIN TerritoryServices ts ON ts.id = at.territoryServiceID
        WHERE at.personID = @personID AND at.attachmentStatusID = 2 AND at.endDate
IS NULL

        IF (@isAt2Close = 1) -- if ter of attach is closing
            BEGIN 
                -- Insert error into ErrorHandlingCampainOfAttach
                DECLARE @ErrorDescr2 NVARCHAR(MAX) SET @ErrorDescr2 = 'TerAttachId:
' + CONVERT(NVARCHAR(MAX),@terAt2ID)
                INSERT INTO [dbo].[ErrorHandlingCampainOfAttach] ([AttachmentsID],[personID],[territoryServiceID],[periodYear],[reasonError],[addDate],[description])
                VALUES (@ID, @personID, @territoryServiceID, @periodYear, 2, GETDATE(),
@ErrorDescr2)
            END
        ELSE
            BEGIN 
                BEGIN TRY
                BEGIN TRANSACTION TranName
                    -- Search active request
                    DECLARE @ID_zapros BIGINT 
                    SELECT @ID_zapros = id FROM Attachments WHERE personID = @personID
AND endDate IS NULL AND attachmentStatusID != 2 AND id != @ID
                    IF (@ID_zapros IS NOT NULL) 
                        BEGIN
                            -- Canseled request

                            -- Block #1
                            -- Create cancel for active request
                            INSERT INTO Attachments (personID,orgHealthCareID,personAddressesID,territoryServiceID,attachmentProfileID,doctorID,
                                causeOfAttachID,careAtHome,senderRequestID,senderSystemID,attachmentStatusID,beginDate,endDate,parentID,userID,registratorID,
                                actualAttachmentID,ConflictAttachment,Node,regDate,isMigrated,isDuplicate,oldPersonID,servApplicationID,Num)
                            SELECT at.personID,at.orgHealthCareID,at.personAddressesID,at.territoryServiceID,at.attachmentProfileID,
at.doctorID,
                                8,at.careAtHome,NULL,NULL, 11, @BeginDate, @BeginDate,
at.id, 
                                at.userID, at.registratorID, at.actualAttachmentID,
NULL,NULL,at.regDate,NULL,0,at.oldPersonID,NULL,at.Num
                            FROM Attachments at 
                            WHERE at.id = @ID_zapros

                            -- Set endDate for active request
                            UPDATE Attachments SET endDate = @BeginDate WHERE id
= @ID_zapros
                        END

                    --Search active attach
                    DECLARE @ID_prikrep BIGINT
                    SELECT @ID_prikrep = id FROM Attachments WHERE personID = @personID
AND endDate IS NULL AND attachmentStatusID = 2
                    IF (@ID_prikrep IS NOT NULL) 
                        BEGIN
                            -- Block #2
                            -- Insert detach
                            INSERT INTO Attachments (personID,orgHealthCareID,personAddressesID,territoryServiceID,attachmentProfileID,doctorID,
                                causeOfAttachID,careAtHome,senderRequestID,senderSystemID,attachmentStatusID,beginDate,endDate,parentID,userID,registratorID,
                                actualAttachmentID,ConflictAttachment,Node,regDate,isMigrated,isDuplicate,oldPersonID,servApplicationID,Num)
                            SELECT at.personID,at.orgHealthCareID,at.personAddressesID,at.territoryServiceID,at.attachmentProfileID,
at.doctorID,
                                8,at.careAtHome,NULL,NULL, 8, @BeginDate, @BeginDate,
at.id, 
                                at.userID, at.registratorID, at.actualAttachmentID,
NULL,NULL,at.regDate,NULL,0,at.oldPersonID,NULL,at.Num
                            FROM Attachments at 
                            WHERE at.id = @ID_prikrep

                            --Set endDate for active attach
                            UPDATE Attachments SET endDate = @BeginDate WHERE id
= @ID_prikrep
                        END

                    -- Attach CA
                    INSERT INTO Attachments (personID,orgHealthCareID,personAddressesID,territoryServiceID,attachmentProfileID,doctorID,
                        causeOfAttachID,careAtHome,senderRequestID,senderSystemID,attachmentStatusID,beginDate,endDate,parentID,userID,registratorID,
                        actualAttachmentID,ConflictAttachment,Node,regDate,isMigrated,isDuplicate,oldPersonID,servApplicationID,Num)
                    SELECT at.personID,at.orgHealthCareID,at.personAddressesID,at.territoryServiceID,at.attachmentProfileID,
at.doctorID,
                        8,at.careAtHome,NULL,NULL, 2, @BeginDate, NULL, at.id, 
                        at.userID, at.registratorID, at.actualAttachmentID, NULL,NULL,at.regDate,NULL,0,at.oldPersonID,NULL,at.Num
                    FROM Attachments at 
                    WHERE at.id = @ID

                COMMIT TRANSACTION TranName

                END TRY
                BEGIN CATCH
                    ROLLBACK TRANSACTION TranName

                    -- Insert error into ErrorHandlingCampainOfAttach
                    INSERT INTO [dbo].[ErrorHandlingCampainOfAttach] ([AttachmentsID],[personID],[territoryServiceID],[periodYear],[reasonError],[addDate],[description])
                    VALUES (@ID, @personID, @territoryServiceID, @periodYear, 3,
GETDATE(),ERROR_MESSAGE())
                END CATCH
            END
    END

FETCH NEXT FROM cur INTO @ID, @personID, @territoryServiceID, @isAtClosed
END
CLOSE cur
DEALLOCATE cur


Запрос для курсора возвращает 6 строк(6 выбраны для примера), то есть все ID уникальные,
ничего не задваивается. Далее в зависимости от определенных условий производятся те
или иные действия, прошу обратить внимание на два блока действий (в комментариях называется
Block#1 и Block#2), именно они ведут себя странно. 

После выполнения запроса на какой-нибудь (тут тоже важно, не всегда на одной и той-же
записи, бывает то на одной то на другой, а то и на двух) записи задваиваются строки
с данными, то есть вставляется две строки у которых все данные кроме автоинкрементного
идентификатора повторяются! Причем если откатить действия и попробовать только на этой
записи на одной (то есть цикл прогнать для одной записи) все завершается отлично! Вот
такие-вот злые электрические силы. Непонятно почему так происходит, подскажите кто-нибудь
что не так, или в каком направлении искать решение? 

P.S. триггеров на вставку данных на таблице Attachments нету. Строки всегда вставляются
после всех действия, то есть допустим первое условие выполняется, вставляется строка
1, затем по второму условию вставляется строка 2, затем строка 3, и в случае если происходит
задвоение строки, то она вставляется самой последней, то есть после строки 3 вставляется
строка 4 идентичная строке 1 (или строке 2 когда как)
    


Ответы

Ответ 1



С помощью Mike удалось найти решение данной проблемы! Тут я изложу все поподробнее вдруг кому-то поможет. Итак, начнем. Результат запроса для курсора: ... как видно никакого дублирования идентификаторов нет С подсказкой Mike(спасибо огромное), в одно из полей (Node) записал id записи в переборе, в результате получил следующее: В первой записи все отлично, не будем ее рассматривать. Вторая запись по списку id = 14308060, personID = 414674754. В результате произошло задвоение (Block #1), но в поле Node видим, что в конце записался идентификатор следующей по порядку записи!!! Ниже приведен результат следующей записи: ... тут все нормально Далее.. Пятая запись id = 148362023, personID = 15300000018501113. В результате прошло задвоение (Block #2), опять же в поле Node идентификатор следующей записи Ниже результат следующей записи в которой все ровно: Итак, все это навело на мысль, значения в переменных остаются прежними если в результате установки возвращается NULL, хотя в каждом цикле переменная объявляется заново. Теперь смотрим что происходит: 1. Выполняется обработка второй записи, так как у нее есть активный запрос то следующее выражение: DECLARE @ID_zapros BIGINT SELECT @ID_zapros = id FROM Attachments WHERE personID = @personID AND endDate IS NULL AND attachmentStatusID != 2 AND id != @ID записывает в переменную @ID_zapros идентификатор 150118746, далее выполняется все как нужно, добавляется ровно столько записей сколько нужно, последней записи, которая дублируется еще пока нет! Далее выполняется обработка третьей записи. У данной записи активного запроса нет, поэтому следующее выражение возвращает NULL SELECT @ID_zapros = id FROM Attachments WHERE personID = @personID AND endDate IS NULL AND attachmentStatusID != 2 AND id != @ID но! в переменную @ID_zapros записывается не NULL(как я предполагал), а остается предыдущее значение! Вот тут то и зарыта собака. И получается что при обработке третьей записи добавляется еще одна запись в с данными о предыдущей записи... с 5 и 6 записью все тоже самое, только уже на другом этапе... Я думал что, так как переменная объявляется внутри цикла, то при каждом объявлении в нее будет записываться NULL, также ошибался что при установки переменной, если результат возвращает NULL, то и в переменную запишется NULL, оказалось совсем не так... Решение довольно простое, обнулять переменную принудительно, я сделал так: DECLARE @ID_zapros BIGINT SELECT @ID_zapros = id FROM Attachments WHERE personID = @personID AND endDate IS NULL AND attachmentStatusID != 2 AND id != @ID IF (@ID_zapros IS NOT NULL) BEGIN --Отказываем запрос --Создаем отказ активному запросу INSERT INTO Attachments (personID,orgHealthCareID,personAddressesID,territoryServiceID,attachmentProfileID,doctorID, causeOfAttachID,careAtHome,senderRequestID,senderSystemID,attachmentStatusID,beginDate,endDate,parentID,userID,registratorID, actualAttachmentID,ConflictAttachment,Node,regDate,isMigrated,isDuplicate,oldPersonID,servApplicationID,Num) SELECT at.personID,at.orgHealthCareID,at.personAddressesID,at.territoryServiceID,at.attachmentProfileID, at.doctorID, 8,at.careAtHome,NULL,NULL, 11, @BeginDate, @BeginDate, at.id, at.userID, at.registratorID, at.actualAttachmentID, NULL,@nvar_ID,at.regDate,NULL,0,at.oldPersonID,NULL,at.Num FROM Attachments at WHERE at.id = @ID_zapros --Закрываем дату активному запросу UPDATE Attachments SET endDate = @BeginDate WHERE id = @ID_zapros SET @ID_zapros = NULL END Извиняюсь за довольно большое изложения, но я впервые здесь, может что-то делаю не так вы уж простите! Еще раз спасибо всем кто откликнулся! Надеюсь это кому-нибудь поможет не напороться на те же грабли)

Ответ 2



Код не самый очевидный, не имея данных сложновато понять, что происходит. Как вариант, для отладки вы можете попробовать добавить output inserted.* для всех блоков insert, что даст вам возможность посмотреть в каком порядке и какие именно данные были вставлены. Пример работы output блока: declare @attachments table (id int, status_id int) insert into @attachments (id, status_id) output 'block #1', inserted.* values (1, 2) insert into @attachments (id, status_id) output 'block #2', inserted.* select 3, 8 Возможно, здесь: SELECT @ID_zapros = id FROM Attachments WHERE ... либо здесь SELECT @ID_prikrep = id FROM Attachments WHERE ... по мере движения курсора выбирается не то, что ожидается.

воскресенье, 9 февраля 2020 г.

Исчезновение курсора мыши при бездействии

#javascript #vuejs #cursor #mouse_event


Подскажите как можно сделать исчезновение курсора мыши, если пользователь не двигает
мышью более 3 секунд. 

Если пользователь начинает двигать мышью, то показать курсор.



new Vue({
  el: "#app",
  data: {
    controlsOpacity: 1,
    isFullscreen: false,


  },
  methods: {
    fullscreen() {
      conosole.log(this.isFullscreen);
      this.isFullscreen == false ? this.isFullscreen = true : this.isFullscreen = false;
    },
    onMouseMove() {
      this.showControls();
      if (this.mouseWait == undefined)
        clearTimeout(this.mouseWait);

      this.mouseWait = setTimeout(() => {
        this.middleControlsOpacity = 0;
        if (this.isFullscreen)
          this.hideControls();
      }, 5000);
    },
    showControls() {
      this.middleControlsOpacity = 1;
      this.controlsOpacity = 1;
      this.$parent.$refs.main.style.cursor = 'default';
    },
    hideControls() {
      this.middleControlsOpacity = 0;
      this.controlsOpacity = 0;
      if (this.isFullscreen) {
        if (this.$parent.$refs.main.mousemove) {
          console.log('move');
        }
        this.$parent.$refs.main.style.cursor = 'none';
      }
    },

  },
  mounted() {

    this.$refs.main.addEventListener('mousemove', this.onMouseMove);
    this.$refs.main.addEventListener('mouseenter', this.showControls);
    this.$refs.main.addEventListener('mouseleave', this.hideControls);

  }

})
body {
  background: #20262E;
  padding: 20px;
  font-family: Helvetica;
}

#app {
  background: #fff;
  border-radius: 4px;
  padding: 20px;
  transition: all 0.2s;
}


Ответы

Ответ 1



Успеть, пока вопрос не закрыли. Пример, все таки применительно к Vue, чтобы лишних слушателей addEventListener не добавляли. В снипет не вставлял, все равно не позволит перейти в полный экран.
Элементы интерфейса в кадре
Закадровые злементы интерфейса.


Ответ 2



~function () { var t; window.addEventListener('mousemove', () => { if (t) { document.documentElement.classList.remove('no-cursor') clearTimeout(t) t = 0 } t = setTimeout(() => document.documentElement.classList.add('no-cursor'), 3000) }); }() .no-cursor, .no-cursor * { cursor: none !important; }

Ответ 3



Примерно вот так : let to = 3000, ts = 0; addEventListener('mousemove', () => { ts = Date.now(); area.style.cursor = "default"; }); setInterval(() => { if (Date.now() - ts > to) area.style.cursor = "none"; }, 99) body, #area{width:100vw;height:100vh;overflow:hidden;margin:0}


суббота, 8 февраля 2020 г.

Закрытие классов базы данных, курсоров

#android #sqlite #cursor


Подскажите пожалуйста, зачем (и как правильно) закрывать:


SQLiteDatabase класс
класс курсора (кстати, как себя поведет адаптер, подключенный к закрытому курсору)
класс-наследник SQLiteHelper


Какова практика использования? В части - открыл/закрыл объект. Может есть какая-то
последовательность закрытия этих объектов?

У меня имеются несколько классов для работы с БД, но в некоторых случаях я подряд
несколько раз использовал открытие бд, на что андроид ругается.. поэтому хочу спросить
у профессионалов, как правильно делать? Может есть подход, о котором я не знаю просто.
    


Ответы

Ответ 1



Насчет курсоров - сейчас рекомендуется использовать класс CursorLoader, который полностью управляет жизненным циклом курсора, следит за его своевременным открытием и закрытием, а так же работает с ним в параллельном потоке, что наилудшим образом сказывается на производительности приложения. При этом в таком классе можно переопределить метод выборки данных, чтобы избавить себя от необходимости заводить еще и ContentProvider, как то требуется в дефолтной реализации. Насчет закрытия БД. В одной, очень содержательной, дискуссии, Диана Хакборн (Dianne Hackborn), далеко не последний человек в подразделении андроид гугла, объясняла всем заинтересованным гражданам, что подключение к БД не только не надо закрывать, а что это еще и не очень то хорошо - закрывать это подключение. При закрытии приложения/класса, использующего подключение к БД, сборщик мусора уничтожит и классы БД и все будет в норме, в противном же случае происходят какие то страшные вещи. UPDATE Вот обсуждение на SO - там есть ссылка на дискуссию гугл-груп андроид-разработчиков, где своим мнением делится Марк Мерфи и Диана. Думаю обсуждение на SO тоже будет интересно. UPDATE2 В своих проектах я использую Realm и вообще не заморачиваюсь с БД SQLite, уже даже и не вспоминаю эти классы-помошники, курсоры, открытия-закрытия , множество всяких оберток и прочий "ужас" ... Все быстро, очень удобно и просто - работаешь, как с ORM (по принципу классов-моделей), но это нативная БД без прослоек и без SQLite

Ответ 2



Закрывать нужно из-за устранения проблем с утечкой памяти и производительностью. Адаптер который пытается подключиться к закрытому курсору выдаст ошибку. Закрывать курсор и SQLiteDatabase классе нужно тогда, когда они закончили работу. В примере ниже я закрываю курсор и бд после того как они отработали: public String getDataFromID(String row, int id) { String query = "SELECT * FROM " + ARTICLES_TABLE_NAME; SQLiteDatabase db = this.getReadableDatabase(); Cursor cursor = db.rawQuery(query, null); cursor.moveToFirst(); String gettingData = cursor.getString(cursor.getColumnIndex(row)); cursor.close(); db.close(); return gettingData; }

четверг, 23 января 2020 г.

Не получается вставить текст .setText(“usd”);

#java #android #textview #adapter #cursor


Создаю список из БД, при этом пытаюсь найти TextView в другом Layout (item.xml),
чтобы вставить в него текст. 
Почему при запуске TextView пустое?

protected void insertElementOfListFromBase(){          
    View itemLayout = View.inflate(this, R.layout.item, null); // 
    TextView money_unit = (TextView) itemLayout.findViewById(R.id.money_unit);   
    money_unit.setText("usd");          
    String[] from = new String[] { SCHETCHIK, STIOMOST };
    int[] to = new int[] { R.id.number, R.id.printStoimost };

    scAdapter = new SimpleCursorAdapter(this, R.layout.item, cursor, from, to);
    Spisok = (ListView) findViewById(R.id.spisok);
    Spisok.setAdapter(scAdapter);
}      

    


Ответы

Ответ 1



Вы создаете View: View itemLayout = View.inflate(this, R.layout.item, null); // Делаете с ним манипуляции: View itemLayout = View.inflate(this, R.layout.item, null); // TextView money_unit = (TextView) itemLayout.findViewById(R.id.money_unit); money_unit.setText("usd"); И никуда его не добавляете. Вы просто не выводите его на экран.

понедельник, 15 июля 2019 г.

Положение курсора при развертывании сниппета в Sublime text

Решил заморочится созданием сниппетов в sublime text для удобства работы, но наткнулся на неприятность при развертывании сниппета курсор улетает в конец всей иерархии а хотелось бы чтобы он вставал там где мне нужно, читал в нете что у него есть подобная настройка, но по моим запросам гугл ничего не выводит((


Ответ

В теле сниппета укажите ${1} - при вставке, курсор будет на этом месте
logger source.ruby
После ввода имени сниппета logger и курсор встанет в следующую позицию
Rails.logger.info '#########################################' Rails.logger.info | Rails.logger.info '#########################################'

четверг, 11 июля 2019 г.

Как узнать позицию курсора мыши относительно экрана?

Как узнать позицию курсора по координатам (X, Y) относительно экрана, не прибегая к средствам Windows.Forms?


Ответ

В WPF есть класс Mouse у которого есть метод GetPosition. Чтобы получить позицию курсора относительно экрана можно использовать метод PointToScreen
private void MainWindow_OnMouseMove(object sender, MouseEventArgs e) { var windowPosition = Mouse.GetPosition(this); var screenPosition = this.PointToScreen(windowPosition);
this.Title = string.Format("{0} --- {1}", windowPosition, screenPosition); }
Или как еще один вариант - использовать PInvoke

воскресенье, 7 июля 2019 г.

Консоль и SetCursorPosition C#

Доброго времени суток. Делаю лабораторную работу по программированию (вопрос не о методе решения) и возникла проблема с консолью.
Суть задачи в том, чтобы сформировать таблицу с данными. Программу нужно научить добавлять и удалять оттуда значения (и другое). Вот как выглядит содержимое в консоли: Код вывода всех окошек, думаю, показывать нет необходимости. Лишь скажу, что после того, как была нажата кнопочка "2" на клавиатуре, выводится второе окошко "Добавление записи", выводится его содержимое, а после курсор устанавливается на нужную позицию (справа от "Наименования").
Итак, проблема первая: по какой-то причине, на какую бы из стрелок я не нажимал, курсор бежит вправо.
Проблема вторая: при попытке усмирить его при помощи Console.SetCursorPosition под новой позицией курсора стирается находящийся там символ.
Для обработки нажатий я использую следующий код:
_cell[0] = new StringBuilder(' '); _cell[1] = new StringBuilder(' '); _cell[2] = new StringBuilder(' '); _cell[3] = new StringBuilder(' '); int currentPos = 0; bool exit = false; ConsoleKeyInfo ck; do { ck = Console.ReadKey(); if (char.IsLetter(ck.KeyChar)) { if (currentPos == 2 || currentPos == 3) { if (char.IsDigit(ck.KeyChar)) _cell[currentPos].Append(ck.KeyChar); } else { _cell[currentPos].Append(ck.KeyChar); } } else { switch (ck.Key) { case ConsoleKey.Enter: //*тут будет сохранение* exit = true; break; case ConsoleKey.Escape: exit = true; break; case ConsoleKey.UpArrow: if (currentPos == 0) currentPos = (Record.ColumnCount - 1); else currentPos--; Console.CursorTop = startY + currentPos; Console.CursorLeft = startX + Record.ColumnNames[currentPos].Length + _cell[currentPos].Length + 2; break; case ConsoleKey.DownArrow: if (currentPos == Record.ColumnCount - 1) currentPos = 0; else currentPos++; Console.CursorTop = startY + currentPos; Console.CursorLeft = startX + Record.ColumnNames[currentPos].Length + _cell[currentPos].Length + 2; break; case ConsoleKey.LeftArrow: Console.CursorLeft -= 2; if (Console.CursorLeft < startX + Record.ColumnNames[currentPos].Length + 2) Console.CursorLeft += 1; break; case ConsoleKey.RightArrow: if (Console.CursorLeft > startX + +Record.ColumnNames[currentPos].Length + (_cell[currentPos].Length)) Console.CursorLeft -= 1; break; } } } while (!exit);
Немного заметок:
currentPos - переменная, отвечающая за строку, на которой находится юзер (то бишь между теми четырьмя строками)
startX, startY - координаты буквы "Н" в слове "Наименование" по отношению к окну (не знаю как выразиться грамотнее). Место, откуда начинается писанина в нижнем окне.
Record.ColumnNames[] - массив с названиями колонок ("Наименование" и остальное).
Как решить проблему (вторую. Первую - просто хочется понять почему так)? Вариант с обыкновенным ReadLine() не хочется реализовывать (хотя тогда все в разы проще было бы), ибо так нельзя будет отловить нажатие стрелок и Escape.


Ответ

Console.ReadKey() читает клавишу с выводом её на экран. Соответственно и символ стрелки выводится на экран тоже. (Возможно, он в вашем шрифте пустой.) Вне зависимости от направления стрелки этот символ выводится в текущую позицию курсора, и курсор сдвигается вправо. При этом он, разумеется, затирает символ, находящийся в новой позиции курсора.
Думаю, вам стоит читать клавишу без отображения:
Console.ReadKey(intercept: true)
и выводить только то, что нужно (цифры/буквы/...).

суббота, 22 июня 2019 г.

SQL, cursor, перебор, добавляется две записи вместо одной

Пытаюсь с помощью курсора перебрать исходные данные и для каждой записи сделать те или иные изменения. Вот сам запрос:
DECLARE @ID bigint --id attachments DECLARE @personID BIGINT DECLARE @territoryServiceID BIGINT DECLARE @isAtClosed BIT
DECLARE @currentServerDate DATETIME = '2016-01-01 01:10:00.000' --this change GETDATE() DECLARE @BeginDate DATETIME SET @BeginDate = @currentServerDate DECLARE @periodYear INT SET @periodYear = DATEPART(YEAR,@currentServerDate) - 1
DECLARE cur cursor LOCAL STATIC FOR SELECT at.id, at.personID, at.territoryServiceID, ts.isClosing FROM Attachments at INNER JOIN Person p ON p.id = at.personID AND p.parentID IS NULL INNER JOIN TerritoryServices ts ON ts.id = at.territoryServiceID LEFT JOIN Attachments at2 ON at2.personID = at.personID AND at2.parentID = at.id AND at2.attachmentStatusID IN (2,11,12) WHERE at.attachmentStatusID = 1 AND at.causeOfAttachID = 8 AND at.endDate IS NOT NULL AND at2.id IS NULL AND p.id IN (15300000019296419,15300000018501113,15300000014988209,414674754,420940229,409531785)
OPEN cur
FETCH NEXT FROM cur INTO @ID, @personID, @territoryServiceID, @isAtClosed WHILE @@FETCH_STATUS = 0 BEGIN DECLARE @personID_NVARCHAR NVARCHAR(MAX) SET @personID_NVARCHAR = CONVERT(NVARCHAR(MAX),@personID) PRINT '1 ('+@personID_NVARCHAR+')'
IF (@isAtClosed = 1) -- if ter of CA is closing BEGIN -- Insert error into ErrorHandlingCampainOfAttach DECLARE @ErrorDescr NVARCHAR(MAX) SET @ErrorDescr = 'TerId: ' + CONVERT(NVARCHAR(MAX),@territoryServiceID) INSERT INTO [dbo].[ErrorHandlingCampainOfAttach] ([AttachmentsID],[personID],[territoryServiceID],[periodYear],[reasonError],[addDate],[description]) VALUES (@ID, @personID, @territoryServiceID, @periodYear, 1, GETDATE(), @ErrorDescr) END ELSE BEGIN DECLARE @terAt2ID BIGINT DECLARE @isAt2Close BIT = 0 SELECT @isAt2Close = ts.isClosing, @terAt2ID = ts.id FROM Attachments at INNER JOIN TerritoryServices ts ON ts.id = at.territoryServiceID WHERE at.personID = @personID AND at.attachmentStatusID = 2 AND at.endDate IS NULL
IF (@isAt2Close = 1) -- if ter of attach is closing BEGIN -- Insert error into ErrorHandlingCampainOfAttach DECLARE @ErrorDescr2 NVARCHAR(MAX) SET @ErrorDescr2 = 'TerAttachId: ' + CONVERT(NVARCHAR(MAX),@terAt2ID) INSERT INTO [dbo].[ErrorHandlingCampainOfAttach] ([AttachmentsID],[personID],[territoryServiceID],[periodYear],[reasonError],[addDate],[description]) VALUES (@ID, @personID, @territoryServiceID, @periodYear, 2, GETDATE(), @ErrorDescr2) END ELSE BEGIN BEGIN TRY BEGIN TRANSACTION TranName -- Search active request DECLARE @ID_zapros BIGINT SELECT @ID_zapros = id FROM Attachments WHERE personID = @personID AND endDate IS NULL AND attachmentStatusID != 2 AND id != @ID IF (@ID_zapros IS NOT NULL) BEGIN -- Canseled request
-- Block #1 -- Create cancel for active request INSERT INTO Attachments (personID,orgHealthCareID,personAddressesID,territoryServiceID,attachmentProfileID,doctorID, causeOfAttachID,careAtHome,senderRequestID,senderSystemID,attachmentStatusID,beginDate,endDate,parentID,userID,registratorID, actualAttachmentID,ConflictAttachment,Node,regDate,isMigrated,isDuplicate,oldPersonID,servApplicationID,Num) SELECT at.personID,at.orgHealthCareID,at.personAddressesID,at.territoryServiceID,at.attachmentProfileID, at.doctorID, 8,at.careAtHome,NULL,NULL, 11, @BeginDate, @BeginDate, at.id, at.userID, at.registratorID, at.actualAttachmentID, NULL,NULL,at.regDate,NULL,0,at.oldPersonID,NULL,at.Num FROM Attachments at WHERE at.id = @ID_zapros
-- Set endDate for active request UPDATE Attachments SET endDate = @BeginDate WHERE id = @ID_zapros END
--Search active attach DECLARE @ID_prikrep BIGINT SELECT @ID_prikrep = id FROM Attachments WHERE personID = @personID AND endDate IS NULL AND attachmentStatusID = 2 IF (@ID_prikrep IS NOT NULL) BEGIN -- Block #2 -- Insert detach INSERT INTO Attachments (personID,orgHealthCareID,personAddressesID,territoryServiceID,attachmentProfileID,doctorID, causeOfAttachID,careAtHome,senderRequestID,senderSystemID,attachmentStatusID,beginDate,endDate,parentID,userID,registratorID, actualAttachmentID,ConflictAttachment,Node,regDate,isMigrated,isDuplicate,oldPersonID,servApplicationID,Num) SELECT at.personID,at.orgHealthCareID,at.personAddressesID,at.territoryServiceID,at.attachmentProfileID, at.doctorID, 8,at.careAtHome,NULL,NULL, 8, @BeginDate, @BeginDate, at.id, at.userID, at.registratorID, at.actualAttachmentID, NULL,NULL,at.regDate,NULL,0,at.oldPersonID,NULL,at.Num FROM Attachments at WHERE at.id = @ID_prikrep
--Set endDate for active attach UPDATE Attachments SET endDate = @BeginDate WHERE id = @ID_prikrep END
-- Attach CA INSERT INTO Attachments (personID,orgHealthCareID,personAddressesID,territoryServiceID,attachmentProfileID,doctorID, causeOfAttachID,careAtHome,senderRequestID,senderSystemID,attachmentStatusID,beginDate,endDate,parentID,userID,registratorID, actualAttachmentID,ConflictAttachment,Node,regDate,isMigrated,isDuplicate,oldPersonID,servApplicationID,Num) SELECT at.personID,at.orgHealthCareID,at.personAddressesID,at.territoryServiceID,at.attachmentProfileID, at.doctorID, 8,at.careAtHome,NULL,NULL, 2, @BeginDate, NULL, at.id, at.userID, at.registratorID, at.actualAttachmentID, NULL,NULL,at.regDate,NULL,0,at.oldPersonID,NULL,at.Num FROM Attachments at WHERE at.id = @ID
COMMIT TRANSACTION TranName
END TRY BEGIN CATCH ROLLBACK TRANSACTION TranName
-- Insert error into ErrorHandlingCampainOfAttach INSERT INTO [dbo].[ErrorHandlingCampainOfAttach] ([AttachmentsID],[personID],[territoryServiceID],[periodYear],[reasonError],[addDate],[description]) VALUES (@ID, @personID, @territoryServiceID, @periodYear, 3, GETDATE(),ERROR_MESSAGE()) END CATCH END END
FETCH NEXT FROM cur INTO @ID, @personID, @territoryServiceID, @isAtClosed END CLOSE cur DEALLOCATE cur
Запрос для курсора возвращает 6 строк(6 выбраны для примера), то есть все ID уникальные, ничего не задваивается. Далее в зависимости от определенных условий производятся те или иные действия, прошу обратить внимание на два блока действий (в комментариях называется Block#1 и Block#2), именно они ведут себя странно.
После выполнения запроса на какой-нибудь (тут тоже важно, не всегда на одной и той-же записи, бывает то на одной то на другой, а то и на двух) записи задваиваются строки с данными, то есть вставляется две строки у которых все данные кроме автоинкрементного идентификатора повторяются! Причем если откатить действия и попробовать только на этой записи на одной (то есть цикл прогнать для одной записи) все завершается отлично! Вот такие-вот злые электрические силы. Непонятно почему так происходит, подскажите кто-нибудь что не так, или в каком направлении искать решение?
P.S. триггеров на вставку данных на таблице Attachments нету. Строки всегда вставляются после всех действия, то есть допустим первое условие выполняется, вставляется строка 1, затем по второму условию вставляется строка 2, затем строка 3, и в случае если происходит задвоение строки, то она вставляется самой последней, то есть после строки 3 вставляется строка 4 идентичная строке 1 (или строке 2 когда как)


Ответ

С помощью Mike удалось найти решение данной проблемы! Тут я изложу все поподробнее вдруг кому-то поможет. Итак, начнем. Результат запроса для курсора:

... как видно никакого дублирования идентификаторов нет
С подсказкой Mike(спасибо огромное), в одно из полей (Node) записал id записи в переборе, в результате получил следующее:
В первой записи все отлично, не будем ее рассматривать. Вторая запись по списку id = 14308060, personID = 414674754. В результате произошло задвоение (Block #1), но в поле Node видим, что в конце записался идентификатор следующей по порядку записи!!!

Ниже приведен результат следующей записи:
... тут все нормально
Далее.. Пятая запись id = 148362023, personID = 15300000018501113. В результате прошло задвоение (Block #2), опять же в поле Node идентификатор следующей записи

Ниже результат следующей записи в которой все ровно:

Итак, все это навело на мысль, значения в переменных остаются прежними если в результате установки возвращается NULL, хотя в каждом цикле переменная объявляется заново. Теперь смотрим что происходит: 1. Выполняется обработка второй записи, так как у нее есть активный запрос то следующее выражение:
DECLARE @ID_zapros BIGINT SELECT @ID_zapros = id FROM Attachments WHERE personID = @personID AND endDate IS NULL AND attachmentStatusID != 2 AND id != @ID
записывает в переменную @ID_zapros идентификатор 150118746, далее выполняется все как нужно, добавляется ровно столько записей сколько нужно, последней записи, которая дублируется еще пока нет!
Далее выполняется обработка третьей записи. У данной записи активного запроса нет, поэтому следующее выражение возвращает NULL
SELECT @ID_zapros = id FROM Attachments WHERE personID = @personID AND endDate IS NULL AND attachmentStatusID != 2 AND id != @ID
но! в переменную @ID_zapros записывается не NULL(как я предполагал), а остается предыдущее значение! Вот тут то и зарыта собака. И получается что при обработке третьей записи добавляется еще одна запись в с данными о предыдущей записи...
с 5 и 6 записью все тоже самое, только уже на другом этапе...
Я думал что, так как переменная объявляется внутри цикла, то при каждом объявлении в нее будет записываться NULL, также ошибался что при установки переменной, если результат возвращает NULL, то и в переменную запишется NULL, оказалось совсем не так...
Решение довольно простое, обнулять переменную принудительно, я сделал так:
DECLARE @ID_zapros BIGINT SELECT @ID_zapros = id FROM Attachments WHERE personID = @personID AND endDate IS NULL AND attachmentStatusID != 2 AND id != @ID IF (@ID_zapros IS NOT NULL) BEGIN --Отказываем запрос
--Создаем отказ активному запросу INSERT INTO Attachments (personID,orgHealthCareID,personAddressesID,territoryServiceID,attachmentProfileID,doctorID, causeOfAttachID,careAtHome,senderRequestID,senderSystemID,attachmentStatusID,beginDate,endDate,parentID,userID,registratorID, actualAttachmentID,ConflictAttachment,Node,regDate,isMigrated,isDuplicate,oldPersonID,servApplicationID,Num) SELECT at.personID,at.orgHealthCareID,at.personAddressesID,at.territoryServiceID,at.attachmentProfileID, at.doctorID, 8,at.careAtHome,NULL,NULL, 11, @BeginDate, @BeginDate, at.id, at.userID, at.registratorID, at.actualAttachmentID, NULL,@nvar_ID,at.regDate,NULL,0,at.oldPersonID,NULL,at.Num FROM Attachments at WHERE at.id = @ID_zapros
--Закрываем дату активному запросу UPDATE Attachments SET endDate = @BeginDate WHERE id = @ID_zapros
SET @ID_zapros = NULL END
Извиняюсь за довольно большое изложения, но я впервые здесь, может что-то делаю не так вы уж простите! Еще раз спасибо всем кто откликнулся! Надеюсь это кому-нибудь поможет не напороться на те же грабли)