Действительно ли возможно добавить логическое Ограничение к Внешнему ключу?

Проблема

Из-за гибридных устройств, которые используют комбинацию сенсорного и мышиного ввода, вы должны иметь возможность динамически изменять состояние / переменную, которая контролирует, должен ли фрагмент кода запускать, если пользователь сенсорный или нет.

Сенсорные устройства также запускают mousemove при нажатии.

Решение

  1. Предположим, что прикосновение ложно при нагрузке.
  2. Подождите, пока не сработает событие touchstart, затем установите для него значение true.
  3. Если сенсорный запуск был запущен, добавьте обработчик перемещения мыши.
  4. Если время между двумя событиями перемещения мыши было менее 20 мс, предположим, что они используют мышь в качестве входных данных. Удалите событие, так как оно больше не нужно, и mousemove - дорогостоящее событие для мышиных устройств.
  5. Как только сенсорный запуск запускается снова (пользователь вернулся к использованию сенсорного ввода), для переменной устанавливается значение true. И повторите процесс, чтобы он определялся динамично. Если каким-то чудом мышиный ход сработал дважды при прикосновении до абсурда быстро (в моем тестировании это практически невозможно сделать в течение 20 мс), следующий сенсорный запуск вернет его к истине.

Протестировано на Safari iOS и Chrome для Android.

Примечание: не уверен на 100% в событиях указателя для MS Surface и т. Д.

Демонстрация Codepen

const supportsTouch = 'ontouchstart' in window;
let isUsingTouch = false;

// `touchstart`, `pointerdown`
const touchHandler = () => {
  isUsingTouch = true;
  document.addEventListener('mousemove', mousemoveHandler);
};

// use a simple closure to store previous time as internal state
const mousemoveHandler = (() => {
  let time;

  return () => {
    const now = performance.now();

    if (now - time < 20) {
      isUsingTouch = false;
      document.removeEventListener('mousemove', mousemoveHandler);
    }

    time = now;
  }
})();

// add listeners
if (supportsTouch) {
  document.addEventListener('touchstart', touchHandler);
} else if (navigator.maxTouchPoints || navigator.msMaxTouchPoints) {
  document.addEventListener('pointerdown', touchHandler);
}
6
задан Pure.Krome 25 June 2009 в 04:59
поделиться

6 ответов

Я провел небольшой тест - в этом случае подход с UDF работает почти в 100 раз медленнее.

Накладные расходы на FK во времени процессора = 375 мс - 297 мс = 78 мс

Накладные расходы UDF во времени ЦП = 7750 мс - 297 мс = 7453 мс

Вот код Sql ...

- настроить вспомогательную таблицу Numbers с 128 КБ строк:

CREATE TABLE dbo.Numbers(n INT NOT NULL PRIMARY KEY)
GO
DECLARE @i INT;
SET @i = 1;
INSERT INTO dbo.Numbers(n) SELECT 1;
WHILE @i<128000 BEGIN
  INSERT INTO dbo.Numbers(n)
    SELECT n + @i FROM dbo.Numbers;
  SET @i = @i * 2;
END;
GO

- таблицы

CREATE TABLE dbo.Animals
(AnimalId INT NOT NULL IDENTITY PRIMARY KEY,
AnimalType TINYINT NOT NULL, -- 1: Mammal, 2:Reptile, etc..
Name VARCHAR(30))
GO
ALTER TABLE dbo.Animals
ADD CONSTRAINT UNQ_Animals UNIQUE(AnimalId, AnimalType)
GO
CREATE FUNCTION dbo.GetAnimalType(@AnimalId INT)
RETURNS TINYINT
AS
BEGIN
DECLARE @ret TINYINT;
SELECT @ret = AnimalType FROM dbo.Animals
  WHERE AnimalId = @AnimalId;
RETURN @ret;
END
GO
CREATE TABLE dbo.Mammals
(AnimalId INT NOT NULL PRIMARY KEY,
SomeOtherStuff VARCHAR(10),
CONSTRAINT Chk_AnimalType_Mammal CHECK(dbo.GetAnimalType(AnimalId)=1)
);
GO

--- заполнение UDF:

INSERT INTO dbo.Animals
  (AnimalType, Name)
SELECT 1, 'some name' FROM dbo.Numbers;
GO
SET STATISTICS IO ON
SET STATISTICS TIME ON
GO
INSERT INTO dbo.Mammals
(AnimalId,SomeOtherStuff)
SELECT n, 'some info' FROM dbo.Numbers;

результаты:

SQL Server parse and compile time: 
CPU time = 0 ms, elapsed time = 2 ms.
Table 'Mammals'. Scan count 0, logical reads 272135, 
    physical reads 0, read-ahead reads 0, lob logical reads 0, 
    lob physical reads 0, lob read-ahead reads 0.
Table 'Numbers'. Scan count 1, logical reads 441, physical reads 0, 
    read-ahead reads 0, lob logical reads 0, lob physical reads 0, 
    lob read-ahead reads 0.

SQL Server Execution Times:
    CPU time = 7750 ms,  elapsed time = 7830 ms.

(131072 row(s) affected)

--- заполнение FK:

CREATE TABLE dbo.Mammals2
(AnimalId INT NOT NULL PRIMARY KEY,
AnimalType TINYINT NOT NULL,
SomeOtherStuff VARCHAR(10),
CONSTRAINT Chk_Mammals2_AnimalType_Mammal CHECK(AnimalType=1),
CONSTRAINT FK_Mammals_Animals FOREIGN KEY(AnimalId, AnimalType)
  REFERENCES dbo.Animals(AnimalId, AnimalType)
);

INSERT INTO dbo.Mammals2
(AnimalId,AnimalType,SomeOtherStuff)
SELECT n, 1, 'some info' FROM dbo.Numbers;

результаты следующие:

SQL Server parse and compile time: 
   CPU time = 93 ms, elapsed time = 100 ms.
Table 'Animals'. Scan count 1, logical reads 132, physical reads 0,
    read-ahead reads 0, lob logical reads 0, lob physical reads 0, 
    lob read-ahead reads 0.
Table 'Mammals2'. Scan count 0, logical reads 275381, physical reads 0,
   read-ahead reads 0, lob logical reads 0, lob physical reads 0, 
   lob read-ahead reads 0.
Table 'Numbers'. Scan count 1, logical reads 441, physical reads 0,
   read-ahead reads 0, lob logical reads 0, lob physical reads 0, 
   lob read-ahead reads 0.

SQL Server Execution Times:
   CPU time = 375 ms,  elapsed time = 383 ms.

- заполнение без какой-либо целостности:

CREATE TABLE dbo.Mammals3
(AnimalId INT NOT NULL PRIMARY KEY,
SomeOtherStuff VARCHAR(10)
);
INSERT INTO dbo.Mammals3
(AnimalId,SomeOtherStuff)
SELECT n,  'some info' FROM dbo.Numbers;

результаты:
Время синтаксического анализа и компиляции SQL Server: Время ЦП = 1 мс, затраченное время = 1 мс.

SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 66 ms.
Table 'Mammals3'. Scan count 0, logical reads 272135, physical reads 0,
    read-ahead reads 0, lob logical reads 0, lob physical reads 0,
    lob read-ahead reads 0.
Table 'Numbers'. Scan count 1, logical reads 441, physical reads 0, 
    read-ahead reads 0, lob logical reads 0, lob physical reads 0, 
    lob read-ahead reads 0.

SQL Server Execution Times:
   CPU time = 297 ms,  elapsed time = 303 ms.

(131072 row(s) affected)

Накладные расходы FK во время ЦП = 375 мс - 297 мс = 78 мс
Накладные расходы UDF во времени ЦП = 7750 мс - 297 мс = 7453 мс

7
ответ дан 8 December 2019 в 14:46
поделиться

Чтобы дать сильную гарантию, вам понадобятся два проверочных ограничения в обе стороны. Если вы ограничиваете только Mammals , кто-то может обновить Animals.AnimalType и получить данные в несогласованном состоянии.

1
ответ дан 8 December 2019 в 14:46
поделиться

Установить уникальное ограничение для животных (AnimalId, AnimalType) Добавьте AnimalType к Mammals и используйте ограничение проверки, чтобы убедиться, что оно всегда равно 1. Используйте FK для ссылки (AnimalId, AnimalType).

6
ответ дан 8 December 2019 в 14:46
поделиться

Вы можете создать ОГРАНИЧЕНИЕ ПРОВЕРКИ для столбца.

ALTER TABLE Mammals
ADD CONSTRAINT CHK_AnimalType CHECK (dbo.fnGetAnimalType(animalId) = 1 );

Теперь вам нужна функция fnGetAnimalType, которая будет возвращать animalType для данного animalId.

Дополнительная информация из MSDN .

2
ответ дан 8 December 2019 в 14:46
поделиться

Я думаю, вы хотите использовать ограничение Check в таблице Mammals.

http://msdn.microsoft.com/en-us/library/ms188258.aspx

0
ответ дан 8 December 2019 в 14:46
поделиться

Посмотрите на структуру аудиоочередей . Это то, что я использую, чтобы получить высокую отметку воды:

AudioQueueRef audioQueue; // Imagine this is correctly set up
UInt32 dataSize = sizeof(AudioQueueLevelMeterState) * recordFormat.mChannelsPerFrame;
AudioQueueLevelMeterState *levels = (AudioQueueLevelMeterState*)malloc(dataSize);

float channelAvg = 0;

OSStatus rc = AudioQueueGetProperty(audioQueue, kAudioQueueProperty_CurrentLevelMeter, levels, &dataSize);
if (rc) {
    NSLog(@"AudioQueueGetProperty(CurrentLevelMeter) returned %@", rc);
} else {    
    for (int i = 0; i < recordFormat.mChannelsPerFrame; i++) {
        channelAvg += levels[i].mPeakPower;
    }
}
free(levels);

// This works because one channel always has an mAveragePower of 0.
return channelAvg;

Вы можете получить пиковую мощность либо в дБ Free Scale (с kAudioQueueProperty_CurrentLevelMeterDB), либо просто в качестве поплавка в интервале [0,0, 1,0] (с kAudioQueueProperty_CurrentLevelMeter).

-121--3879827-

Почему не KISS:

class PlayerPosition {
    public enum Position {
        Quarterback,
        Runningback,
        DefensiveEnd,
        Linebacker
    }

    public enum Type {
        Offense,
        Defense
    }


    public static Type GetTypeForPosition(Position position) {
        switch (position) {
            case Quarterback:
            case Runningback:
                return Type.Offense;
            case DefensiveEnd:
            case Linebacker:
                return Type.Defense;

        }
    }
}
-121--2489287-

Это звучит как наследование таблицы - я недавно задал вопрос (не могу связать, потому что я здесь слишком новый!), ответ которого привел к поиску этого решения .

Я работаю с денежными транзакциями, где транзакция является родительской таблицей, а типы транзакций, такие как чек, банковский перевод и CC, являются дочерними таблицами. Используя таблицу подстановки для типов транзакций, ограничений внешнего ключа и вычисляемых столбцов, я смог применить ограничение типа к каждой из дочерних таблиц.

Ознакомьтесь со статьей для получения подробной информации о реализации.

0
ответ дан 8 December 2019 в 14:46
поделиться
Другие вопросы по тегам:

Похожие вопросы: