Опытный разработчик не так давно зашёл в .Net и поставил цель получить сертификат Microsoft. Свой ежедневный прогресс он описывает на канале .Net Разработчик. Заметки об изученном материале, советы по повышению производительности и поддержке мотивации, ин
user_id, есть три возможных варианта:
1) Создать структуру со всеми внешними связями таблицы users и получать все данные в неё. Но это приведёт к очень дорогостоящим запросам и возвращает много данных из всех внешних таблиц, которые в большинстве случаев не требуются.
2) Делать несколько запросов на сервер:
GET /users GET users/1/experienceЭто пример неполной выборки, так как у одной конечной точки недостаточно данных. Но множественные сетевые вызовы замедляют процесс и влияют на работу пользователя. Кроме того, в случае списка неполная выборка усугубляется тем, что нам нужно сделать запрос опыта для каждого пользователя в списке, и мы сталкиваемся с проблемой n+1 запроса.
GET /users GET users/1/experience GET users/2/experience … GET users/n/experience3) Создать специальный контроллер, который возвращает структуру данных, соответствующую требованиям клиента на данный момент времени.
GET /user-experienceЭто и делается в большинстве реальных случаев в REST API. С другой стороны, простой запрос GraphQL будет без проблем работать без каких-либо дополнительных изменений на стороне сервера. Запрос будет выглядеть примерно так:
{
users{
name
experience{
organization
title
duration
}
}
}
Да, можно использовать REST, создавать контроллеры (методы) под требования клиента. Но есть большой недостаток. Мы сформировали тесную связь клиентского представления с внутренними контроллерами API, поэтому потребуется больше усилий, чтобы обрабатывать запросы клиентов. Пользовательский контроллер возвращает данные в зависимости от того, что хочет отобразить представление, поэтому, когда требования изменятся, придётся менять как представление, так и контроллер.
Например, по прошествии времени в списке потребовалось выводить не опыт, а последнюю транзакцию пользователя. С REST нужно будет внести соответствующие изменения в представление, но также придётся изменить и контроллер (добавить метод), и путь. То есть изменение требований клиента сильно влияет на то, что должно быть возвращено сервером.
С GraphQL нам не нужно будет вносить какие-либо изменения на стороне сервера. Изменение внешнего запроса будет минимальным:
{
users{
name
transactions{
amount
type
}
}
}
Никакого рефакторинга серверного API, развертывания и тестирования — это означает экономию времени и усилий!
Итого
GraphQL имеет ряд преимуществ перед REST во многих областях. Первоначальная настройка GraphQL может занять больше времени, но существует множество скаффолдеров, которые облегчают эту работу. И даже если поначалу это займет больше времени, это даст вам преимущество в долгосрочной перспективе.
Источник: www.freecodecamp.org/news/gr…rest-api{
"id": 1,
"name": "John Smith",
"username": "jsmith",
"email": "[email protected]",
"title": "Software Engineer",
"phone": "9876543210",
"about": "As a software engineer my daily routine revolves around writing cleancode, maintaining infrastructure, and building scalable software systems.",
"website": "https://www.jsmith.tech",
"gender": "MALE",
"city": "Denver",
"state": "Colorado",
"country": "US",
…
}
Это добавляет в каждый запрос дополнительные данные, которые не требуются клиенту, что увеличивает размер полезной нагрузки и влияет на общее время ответа на запрос. Ещё хуже, если данные выбираются из нескольких таблиц, даже если клиенту этого не нужно.
GraphQL позволяет отправить запрос только нужных данных, который будет выглядеть примерно так:
{
user(id: 1){
name
title
about
}
}
Окончание следует…
Источник: www.freecodecamp.org/news/gr…rest-apiImmutableHashSet<T> — коллекция уникальных элементов и ImmutableSortedSet<T> — отсортированная коллекция уникальных элементов. Эти типы из пространства имён System.Collections.Immutable обладают похожим интерфейсом:
var hs = ImmutableHashSet<int>.Empty; hs = hs.Add(13); hs = hs.Add(7); // Выводит "7" и "13" в непредсказуемом порядке foreach (int item in hs) Console.WriteLine(item); hs = hs.Remove(7);Отсортированное множество допускает индексирование по аналогии со списком:
var shs = ImmutableSortedSet<int>.Empty; shs = shs.Add(13); shs = shs.Add(7); // Выводит "7", затем "13" foreach (int item in shs) Console.WriteLine(item); int smallest = shs[0]; // 7 shs = shs.Remove(7);Несортированные и отсортированные множества обладают схожим быстродействием: O(log N) для добавления, удаления. Важное примечание: обращение по индексу в сортированном множестве также выполняется за время O(log N), а не O(1), как и у
ImmutableList<T>. Это означает, что в данной ситуации действует та же рекомендация: используйте foreach вместо for там, где это возможно.
Рекомендую использовать несортированное множество, если только вы не уверены в том, что оно должно быть отсортированным. Это позволит использовать неизменяемое множество в большем количестве ситуаций.
Неизменяемые множества полезны, но заполнение большого неизменяемого множества может быть медленной операцией. У многих неизменяемых коллекций имеются специальные построители, которые могут использоваться для быстрого их построения в изменяемом виде с последующим преобразованием в неизменяемую коллекцию. Это относится ко многим неизменяемым коллекциям, но, на мой взгляд, они особенно полезны для неизменяемых множеств.
См. также:
- Неизменяемые стеки и очереди
- Неизменяемые списки
Источник: Стивен Клири “Конкурентность в C#”. 2-е межд. изд. — СПб.: Питер, 2020. Глава 9.OnModelCreating с помощью метода IsTemporal:
protected override void OnModelCreating(ModelBuilder builder)
{
builder
.Entity<Product>()
.ToTable("Products", b => b.IsTemporal());
}
Затем миграции EF Core либо создадут эти таблицы как темпоральные, либо, если таблицы уже существуют, они будут преобразованы в темпоральные. Миграция добавляет два скрытых столбца datetime2 с именами PeriodStart и PeriodEnd. Они представляют диапазон времени, в течение которого существовали эти данные в строке. Эти столбцы сопоставляются с теневыми свойствами в модели EF Core, что позволяет использовать их в запросах.
Запрос исторических данных
В большинстве случаев темпоральные таблицы используются точно так же, как и любые другие. Объекты добавляются, запрашиваются, обновляются и удаляются обычным способом.
EF Core поддерживает несколько операторов запросов к темпоральным таблицам:
- TemporalAsOf: возвращает строки, которые были активны в указанное время UTC. Это одна строка из таблицы истории для данного первичного ключа.
- TemporalAll: возвращает все строки в исторических данных. Обычно это много строк из таблицы истории для данного первичного ключа.
- TemporalFromTo: возвращает все строки, которые были активны между двумя заданными значениями времени UTC. Это может быть много строк из таблицы истории для данного первичного ключа.
- TemporalBetween: то же, что и TemporalFromTo, за исключением того, что включаются только строки, которые стали активными с начала периода.
- TemporalContainedIn: возвращает все строки, которые начали быть активными и закончили быть активными между двумя заданными значениями времени UTC. Это может быть много строк из таблицы истории для данного первичного ключа.
Например, следующий запрос вернёт цены продукта между двумя датами from и to:
var prices = context.Products
.TemporalBetween(from, to)
.OrderBy(p =>
EF.Property<DateTime>(p, "PeriodStart"))
.Where(p => p.Name == name)
.Select(p =>
new {
Product = p,
PeriodStart =
EF.Property<DateTime>(p, "PeriodStart"),
PeriodEnd =
EF.Property<DateTime>(p, "PeriodEnd")
})
.ToList();
Источник: devblogs.microsoft.com/dotnet/…core-6-0List<T>.
ImmutableList<T> из пространства имён System.Collections.Immutable поддерживает примерно те же методы, что и List<T>:
var list = ImmutableList<int>.Empty; list = list.Insert(0, 13); list = list.Insert(0, 7); // Выводит "7", затем "13". foreach (int item in list) Console.WriteLine(item); list = list.RemoveAt(1);
ImmutableList<T> не имеет открытого конструктора; вы начинаете с извлечения пустого ImmutableList<T> с помощью ImmutableList<T>.Empty. Затем можете вызвать методы, такие как Add и AddRange, для заполнения коллекции. Обратите внимание, что эти методы возвращают новый объект. Когда вы добавляете или удаляете элементы из неизменяемого списка, создается копия исходного списка с добавленными или удаленными элементами, а исходный список не изменяется.
Во внутренней реализации неизменяемого списка используется двоичное дерево, чтобы экземпляры могли максимизировать объем памяти, используемый совместно с другими экземплярами. В результате для некоторых распространенных операций существуют различия в быстродействии.
Быстродействие List<T>:
Add ~ O(1)
Insert - O(N)
RemoveAt - O(N)
Item[индекс] - O(1)
Быстродействие ImmutableList<T> - O(log N) для всех операций, а не O(1), как можно было бы ожидать. Если вы замените List<T> на ImmutableList<T> в существующем коде, следует учесть, как ваши алгоритмы обращаются к элементам коллекции.
Например, следует использовать foreach вместо for там, где это возможно. Цикл foreach по ImmutableList<T> выполняется за время O(N), тогда как цикл for по той же коллекции выполняется за время O(N * log N).
ImmutableList<T> — хорошая структура данных общего назначения, но из-за различий в быстродействии вы не можете бездумно заменить ей все List<T>. List<T> часто используется по умолчанию — именно эту структуру данных следует использовать, если только у вас нет веских причин для выбора другой коллекции. Коллекция ImmutableList<T> не настолько распространена; следует тщательно проанализировать другие неизменяемые коллекции и выбрать ту, которая лучше всего подходит для вашей ситуации.
В документации ImmutableList<T>.Builder в MSDN рассматривается эффективный способ заполнения неизменяемых списков.
См. также Неизменяемые стеки и очереди
Источник: Стивен Клири “Конкурентность в C#”. 2-е межд. изд. — СПб.: Питер, 2020. Глава 9.const определяется во время компиляции. Основная особенность в том, что константа должна иметь значение при объявлении. Поэтому только примитивные типы (int, string, double и т.п.) можно использовать в качестве констант. Кроме того, константы по умолчанию являются статическими, т.е. не нужно использовать экземпляр класса для доступа к открытой константе.
public class Constant
{
public const string myVar = "Constant";
}
Console.WriteLine(Constant.myVar);
Когда использовать
Для значений примитивных типов, которые никогда не изменятся. При компиляции все использования константы заменяются её значением, поэтому если изменить значение константы, то придётся перекомпилировать все сборки, где она используется.
2. Readonly
Ключевое слово readonly означает, что переменной может быть присвоено значение во время выполнения либо при инициализации, либо через нестатический конструктор.
public class Readonly
{
public readonly string var1 = "Readonly1";
public readonly string var2;
public Readonly()
{
var2= "Readonly2";
}
}
var obj = new Readonly();
Console.WriteLine(obj.var2);
Ключевое слово readonly позволяет инициализировать переменную либо во время компиляции, либо во время выполнения, тогда как const инициализируется во время компиляции. Кроме того, мы должны использовать экземпляр класса для доступа к переменной только для чтения.
Когда использовать
Когда нужно инициализировать переменную во время построения класса, а затем она никогда не будет изменена.
3. Static Readonly
Ключевое слово static используется для объявления статических членов. Значение переменной static readonly может быть присвоено во время выполнения либо при инициализации, либо через статический конструктор.
public class StaticReadonly
{
public static readonly string var1 = "First";
public static readonly string var2;
static StaticReadonly()
{
var2 = "Second";
}
}
Console.WriteLine(StaticReadonly.var2);
Когда использовать
Статические переменные только для чтения похожи на константы. Отличие в том, что, если значение будет изменено, изменения будут видны во всех сборках, где оно используется, без необходимости их перекомпиляции.
Источник: enlear.academy/const-v…20aa0b57