Js - однопоточная.
Браузер можно разделить на три части:
1) Event Loop
2 ) Web API
3) Очередь событий
Событие Loop запускается вечно, т. Е. Тип бесконечного цикла. Очередь ожидания - это то, где вся ваша функция нажимается на какое-либо событие (пример: нажмите) this один за другим выполняется в очереди и помещается в цикл «Событие», который выполняет эту функцию и подготавливает ее для следующего после первого запуска. Это означает, что выполнение одной функции не начинается до тех пор, пока функция, перед которой она в очереди не будет выполнена цикл событий.
Теперь давайте подумаем, что мы поставили две функции в очереди, чтобы получить данные с сервера, а другой использует эти данные. Мы сначала нажали функцию serverRequest () в очереди, а затем применили функцию Data () , Функция serverRequest переходит в цикл событий и делает вызов на сервер, так как мы никогда не знаем, сколько времени потребуется для получения данных с сервера, поэтому ожидается, что этот процесс займет много времени, и поэтому мы заняли наш цикл событий, тем самым повесив нашу страницу, вот где Web API входит в эту роль, он принимает эту функцию из цикла событий и обращается к серверу, создающему цикл событий, так что мы можем выполнить следующую функцию из очереди. Следующая функция в очереди - useData (), которая идет в цикле, но из-за отсутствия данных отходы и выполнение следующей функции продолжаются до конца очереди (это называется Async-вызовом, то есть мы можем сделать что-то еще, пока не получим данные)
Предположим, что наша функция serverRequest () имела оператор возврата в код, когда мы возвращаем данные с сервера Web API, будет выталкивать его в очередь в конце очереди. По мере того, как он заканчивается в очереди, мы не можем использовать его данные, поскольку в нашей очереди нет функции, чтобы использовать эти данные. Таким образом, невозможно вернуть что-то из Async Call.
Таким образом, решение этой проблемы callback или обещают .
A Изображение из одного из ответов здесь, правильно объясняет использование обратного вызова ... Мы (функция, использующая данные, возвращаемые с сервера), чтобы вызвать вызывающий сервер.
function doAjax(callbackFunc, method, url) { var xmlHttpReq = new XMLHttpRequest(); xmlHttpReq.open(method, url); xmlHttpReq.onreadystatechange = function() { if (xmlHttpReq.readyState == 4 && xmlHttpReq.status == 200) { callbackFunc(xmlHttpReq.responseText); } } xmlHttpReq.send(null); }
В моем коде он называется
function loadMyJson(categoryValue){ if(categoryValue==="veg") doAjax(print,"GET","http://localhost:3004/vegetables"); else if(categoryValue==="fruits") doAjax(print,"GET","http://localhost:3004/fruits"); else console.log("Data not found"); }
Прочитайте здесь новые методы в ECMA (2016/17) для создания асинхронного вызова (@Felix Kling Answer сверху) https://stackoverflow.com/a/14220323/7579856
Это неприятная проблема, для которой я не знаю никакого элегантного решения.
Предположим, что у вас есть эти комбинации клавиш, и вы хотите только выделить отмеченные (*).
Id1 Id2
--- ---
1 2 *
1 3
1 6
2 2 *
2 3 *
... (many more)
Как сделать так, чтобы Entity Framework была счастлива? Давайте посмотрим на некоторые возможные решения и посмотрим, хороши ли они.
Join
(или Contains
) с парами Лучшим решением было бы создать список пар, который вы хотите, например Tuples, (List<Tuple<int,int>>
) и соединить данные базы данных с этим списком:
from entity in db.Table // db is a DbContext
join pair in Tuples on new { entity.Id1, entity.Id2 }
equals new { Id1 = pair.Item1, Id2 = pair.Item2 }
select entity
В LINQ для объектов это было бы прекрасно, но слишком плохо, EF генерирует исключение, подобное
Невозможно создать постоянное значение типа «System.Tuple`2 (...) В этом контексте поддерживаются только примитивные типы или типы перечисления.
blockquote>, который является довольно неуклюжим способом сказать вам, что он не может перевести этот оператор в SQL, потому что
Tuples
не является списком примитивных значений (например,int
илиstring
). 1. По той же причине аналогичный оператор, использующийContains
(или любой другой оператор LINQ), потерпит неудачу.Решение 2: In-memory
Конечно, мы могли бы превратить проблему в простой LINQ для таких объектов:
from entity in db.Table.AsEnumerable() // fetch db.Table into memory first join pair Tuples on new { entity.Id1, entity.Id2 } equals new { Id1 = pair.Item1, Id2 = pair.Item2 } select entity
Нечего и говорить, что это нехорошее решение.
db.Table
может содержать миллионы записей.Решение 3: Два оператора
Contains
Итак, давайте предложим EF два списка примитивных значений,
[1,2]
дляId1
и[2,3]
дляId2
. Мы не хотим использовать join (см. Примечание к стороне), поэтому давайте использоватьContains
:from entity in db.Table where ids1.Contains(entity.Id1) && ids2.Contains(entity.Id2) select entity
Но теперь результаты также содержат объект
{1,3}
! Ну, конечно, эта сущность идеально соответствует двум предикатам. Но давайте иметь в виду, что мы приближаемся.Решение 4: Один
Contains
с вычисленными значениямиРешение 3 не удалось, потому что два отдельных
Contains
не только фильтруют комбинации своих значений. Что делать, если мы сначала создадим список комбинаций и попытаемся сопоставить эти комбинации? Из решения 1 известно, что этот список должен содержать примитивные значения. Например:var computed = ids1.Zip(ids2, (i1,i2) => i1 * i2); // [2,6]
и оператор LINQ:
from entity in db.Table where computed.Contains(entity.Id1 * entity.Id2) select entity
Есть некоторые проблемы с этим подходом. Во-первых, вы увидите, что это также возвращает объект
{1,6}
. Комбинационная функция (a * b) не дает значений, которые однозначно идентифицируют пару в базе данных. Теперь мы могли бы создать список строк, таких как["Id1=1,Id2=2","Id1=2,Id2=3]"
и dofrom entity in db.Table where computed.Contains("Id1=" + entity.Id1 + "," + "Id2=" + entity.Id2) select entity
(Это будет работать в EF6, а не в более ранних версиях).
Это становится довольно грязным. Но более важной проблемой является то, что это решение не является sargable , что означает: он обходит любые индексы базы данных на
Id1
иId2
, которые могли быть использованы иначе. Это будет очень плохо.Решение 5: Лучшее из 2 и 3
. Единственное жизнеспособное решение, о котором я могу думать, это комбинация
Contains
иjoin
в памяти: сначала сделайте оператор contains, как в решении 3. Помните, что он приблизился к тому, что мы хотели. Затем уточните результат запроса, присоединив результат как список в памяти:var rawSelection = from entity in db.Table where ids1.Contains(entity.Id1) && ids2.Contains(entity.Id2) select entity; var refined = from entity in rawSelection.AsEnumerable() join pair in Tuples on new { entity.Id1, entity.Id2 } equals new { Id1 = pair.Item1, Id2 = pair.Item2 } select entity;
Это не изящно, беспорядочно все-таки возможно, но пока это единственное масштабируемое решение этой проблемы, которое я нашел, и применяется в моем собственном коде.
Решение 6: Создайте запрос с предложениями OR
Используя построитель Predicate, такой как Linqkit или альтернативы, вы можете построить запрос, содержащий предложение OR для каждый элемент в списке комбинаций. Это может быть жизнеспособным вариантом для действительно коротких списков. С несколькими сотнями элементов запрос начнет работать очень плохо. Поэтому я не считаю это хорошим решением, если вы не можете быть на 100% уверены, что всегда будет небольшое количество элементов. Один из вариантов этой опции можно найти здесь здесь .
1 Как забавная заметка, EF делает создание инструкции SQL, когда вы присоединяетесь к примитивный список, например
from entity in db.Table // db is a DbContext join i in MyIntegers on entity.Id1 equals i select entity
Но сгенерированный SQL, ну, абсурд. Пример в реальной жизни, где
MyIntegers
содержит только 5 (!) Целых чисел, выглядит следующим образом:SELECT [Extent1].[CmpId] AS [CmpId], [Extent1].[Name] AS [Name], FROM [dbo].[Company] AS [Extent1] INNER JOIN (SELECT [UnionAll3].[C1] AS [C1] FROM (SELECT [UnionAll2].[C1] AS [C1] FROM (SELECT [UnionAll1].[C1] AS [C1] FROM (SELECT 1 AS [C1] FROM ( SELECT 1 AS X ) AS [SingleRowTable1] UNION ALL SELECT 2 AS [C1] FROM ( SELECT 1 AS X ) AS [SingleRowTable2]) AS [UnionAll1] UNION ALL SELECT 3 AS [C1] FROM ( SELECT 1 AS X ) AS [SingleRowTable3]) AS [UnionAll2] UNION ALL SELECT 4 AS [C1] FROM ( SELECT 1 AS X ) AS [SingleRowTable4]) AS [UnionAll3] UNION ALL SELECT 5 AS [C1] FROM ( SELECT 1 AS X ) AS [SingleRowTable5]) AS [UnionAll4] ON [Extent1].[CmpId] = [UnionAll4].[C1]
Есть n-1
UNION
s. Конечно, это не масштабируемо.Позднее дополнение: где-то по дороге к версии EF 6.1.3 это значительно улучшилось.
UNION
s стали проще, и они больше не вложены. Раньше запрос отказывался от менее 50 элементов в локальной последовательности (исключение SQL: Некоторая часть вашего оператора SQL слишком глубоко вложена .) Не вложенныеUNION
разрешают локальные последовательности до несколько тысяч (!) элементов.
2 Поскольку оператор
Contains
масштабируется: Масштабируемый Содержит метод LINQ для SQL-сервера
Вы можете создать коллекцию строк с такими ключами, как это (я предполагаю, что ваши ключи имеют тип int):
var id1id2Strings = listOfIds.Select(p => p.Id1+ "-" + p.Id2);
Затем вы можете просто использовать «Содержит» на вашем db:
using (dbEntities context = new dbEntities())
{
var rec = await context.Table1.Where(entity => id1id2Strings .Contains(entity.Id1+ "-" + entity.Id2));
return rec.ToList();
}
Вам нужен набор объектов, представляющих ключи, которые вы хотите запросить.
class Key
{
int Id1 {get;set;}
int Id2 {get;set;}
Если у вас есть два списка, и вы просто проверяете, что каждое значение отображается в их соответствующем списке, тогда вы получаете декартову продукт списков, что, скорее всего, не то, что вы хотите. Вместо этого вам нужно запросить конкретные комбинации
List<Key> keys = // get keys;
context.Table.Where(q => keys.Any(k => k.Id1 == q.Id1 && k.Id2 == q.Id2));
Я не совсем уверен, что это действительное использование Entity Framework; у вас могут возникнуть проблемы с отправкой типа Key
в базу данных. Если это произойдет, вы можете быть творческими:
var composites = keys.Select(k => p1 * k.Id1 + p2 * k.Id2).ToList();
context.Table.Where(q => composites.Contains(p1 * q.Id1 + p2 * q.Id2));
Вы можете создать изоморфную функцию (простые числа хороши для этого), что-то вроде хэш-кода, который вы можете использовать для сравнения пары значений. Пока мультипликативные факторы являются совместными, этот шаблон будет изоморфным (взаимно однозначным), т. Е. Результат p1*Id1 + p2*Id2
однозначно идентифицирует значения Id1
и Id2
, если простые числа правильно выбран.
Но тогда вы оказываетесь в ситуации, когда вы реализуете сложные концепции, и кто-то должен будет это поддержать. Вероятно, лучше написать хранимую процедуру, которая принимает действительные ключевые объекты.
В отсутствие общего решения, я думаю, есть две вещи, которые следует учитывать:
Например, проблема, ведущая меня к этому вопросу, заключалась в том, чтобы запросить строки порядка, где ключ - идентификатор заказа + номер строки заказа + тип заказа , и источник имел тип неявного типа. То есть тип заказа был константой, идентификатор заказа уменьшал бы запрос, заданный для порядка строк соответствующих заказов, и обычно их было бы 5 или меньше.
Чтобы перефразировать: если у вас есть составной ключ, изменения в том, что один из них имеет очень мало дубликатов. Примените решение 5 сверху.
В случае составного ключа вы можете использовать другой список идентификаторов и добавить условие для этого в свой код
context.Table.Where(q => listOfIds.Contains(q.Id) && listOfIds2.Contains(q.Id2));
или вы можете использовать трюк друг друга, создавая список своих ключей, добавляя их
listofid.add(id+id1+......)
context.Table.Where(q => listOfIds.Contains(q.Id+q.id1+.......));