All streams
Search
Write a publication
Pull to refresh
4
0
Send message
Нажимаю «ответить» всегда. Кто глючит не знаю.

Встречный вопрос, вы в своих спецификациях ногу не сломали? Долго ли ищите корень зла при правке багов?
В этой статье столько патернов накидано, за все я не говорил.

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

Для таких вещей я делаю просто Extension метод, который накладывает фильтр как тунель.
public interface IHasPrice
{
    public double Price { get; }
}

public class Product : IHasPrice
{
    ...
    public double Price { get; set; }
}

public static IQueryable<T> FilterNicePrice<T>(this IQueryable<T> query)
  where T : IHasPrice
{
    return query.Where(e => e.Price > 15);
}

Инлайнятся выражения. И много бойлерплейт кода забирается. Например (из реального пректа).

public static class SqlExt
{
	[ExpressionMethod("ToDurationImpl")]
	public static int? ToDuration(DateTime? start, DateTime? end)
	{
		throw new NotImplementedException();
	}

	private static Expression<Func<DateTime?, DateTime?, int?>> ToDurationImpl()
	{
		return (start, end) => start != null && end != null
			? (Sql.DateDiff(Sql.DateParts.Minute, start, end) < 0
				? Sql.DateDiff(Sql.DateParts.Minute, start, end) + 1140
				: Sql.DateDiff(Sql.DateParts.Minute, start, end))
			: null;
	}
}


Теперь я могу спокойно использовать SqlExt.ToDuration(е.StartDate, e.EndDate) в фильтре или в проекции. И конечно же дальше уже лавинно можно в таких методах обращаться к другим таким же методам. Строятся хелперы и написание запроса превращается в легкую прогулку.

Похожим способом задаются асоциации, например тут.

Вот из-за чего я плюнул на EF. Такое в linq2db делается с полпинка через ExpressionMethod атрибут blog.linq2db.com. И даже больше асоциации также можно описывать как деревья выражений, когда вам нужно получать только те записи которые удволетворяют условию.

И встречный вопрос, можете ли вы удалить/изменить записи по выражению? Нет, нужны костыли или другие либы-костыли вроде ZZZExtension. Учитывая что средний пользователь понимает что EF такое не может, просто пишет в лоб — наполнить ченж трекер и дождаться результата за пол часа.
Как же оно красиво все работает первые пол года, репозитории настроены, тесты бегают. Хотя нет, репозитории тоже обросли костылями, когда надо cross repository запросы делать. Вот так и живем, нас учат как писать, а мы думаем как в этом всем выжить.
И придуман же выход, нафиг linq запросы — Dapper. Все, мы скатились назад.

Пост хорош, дает стимул мозгу и позволяет продумать стратегию как работать с linq запросами. Это деревья и надо понимать почему. Шишки в этом набиты серьезные, зато теперь такие хелперы я пишу с первого раза, ну со второго ;)
Вот наинклюдят, так что пол базы затягивается ;) Шучу конечно. Но я такого насмотрелся за свое время, что жуть берет. Eager loading еще та палка о двух концах. А человеку всего-то надо было сообщения почитать, а оно толпу ентитей протянуло и закешировало.

Вот так без, и черт, я очень надеюсь тут не надо писать AsNoTracking()
var query = db.Foos
   .Where(a => a.Id = id)
   .Select(a => a.Bar.Baz.Message);

foreach (var m in query) 
{
    Console.WriteLine(m);
}
Разнес и просел перформанс. Я в таких случаях всегда рекомендую не репозиторить без надобности, а попробовать писать прямо через ORM, насоздавав необходимых хелперов.

Я противник патерна репозиторий и уж тем более generic repository, так как считаю что вместо улучшения кода они порождают тучу затычек да и время разработки увеличивают раза в два.

Хотите тестировать, тестируйте на эталонной базе функциональными тестами. Да это медленней, но это чертовски как надежней. И констрейнты срабатывают и хранимки дергаются.
Да, точно, не использует. Я уже и не вспомню какой у них для этого патерн. EntityServices?
А join на этот запрос вы сделать можете? А если там еще и группировка или урезанная по нескольким полям выборка?

Я веду к тому что в нормальных ORM используется не только фильтрация, а и в полный рост query decomposition. Склеиваете такие маленькие подзапросы, накладываея ограничения по доступу, и на выходе получаете взрослый оптимизированный запрос. Поверьте оптимизированный, намного лучше чем руками бы писал.

Сколько не смотрел на другие языки и их ORM, только .NET с его IQueryable позволяет такое делать типобезопасно и предсказуемо. Естественно зависит от linq провайдера. Мой выбор давно пал на linq2db
Вот уж не знаю от кто тут трешевый, но для меня code-first делает видимую легкость написания приложения, где-то первые две недели. Если вы не заморачиваетесь перформансом то и первый год. Потом продакшин и жестокая реальность — так базы данных не проектируют.

В нашем ORM есть случи когда пользователь создает тикеты на микрооптимизации то на параметр, то на использование той или другой функции. И мы соглашаемся что такое надо исправлять, ведь если мы не дадим ему этой возможности, ему придется писать голый SQL, что сводит усилия ORM на нет.

Также code-first по своей сути исключает возможность cross database запросов, по крайней мере в мире .NET
Вот и нашелся человек который любит Django, а я уже начал жалеть питонистов. Я посмотрю как мы разрулим мою новую схему базы данных на нем, но что-то мне подсказывает это будет печально и превратится в склейку строк.
Перформанс из рук вон плох, и это даже не из-за Django, а из-за того что он мало чего позволяет из мира SQL.
Не к автору статьи: я вас прошу не путать Active Record ORM с ORM близкими к SQL. К первым относятся практически все новомодные свистелки типа EF, Hibernate, Django, etc. Ко вторым отношу linq2db, и, возможно SqlAlchemy (извините не особо питонирую). Если вам не хватает гибкости — вперед есть альтернативы.
И что примечательно, что active record — это то что принимается легче чем SQL. Естственно, на них легче накрутить патерны репозиторий, UoW, и вообще забыть что такое база данных и как ее готовят. И тут всплакнули алгоритмы оптимиций баз данных, их просто обошли сторной,. Да и зачем, есть id, мы по ней прыгаем, по них удаляем, джоины практически на клиентской стороне делаем. А кеши! Вот она панацея от неугодного «кверяния».
Да не обижу знатоков EF, знающих как обходить его ухабы, просто советую не зацикливайтесь.
Спасибо за статью. Я также не поленился и нашел те < 50 строчек кода, которые включают поддержку Turbolinks в ASP.NET MVC. Надо будет на досуге поэкспериментировать пока Blazor еще не готов.
Для тех кому надо было пачку обьектов удалять или апдейтть или копировать в другую таблицу или… Добро пожаловать в тестеры!
linq2db.EntityFrameworkCore
А не получается ли что вы пишете новый облегченный JOOQ? Хотя, почему бы Котлину не поддержать Expression Tree, также как async await. Вот и появились бы первые провайдеры баз данных на JavaVM без текущих ограничений. Думаю что они думают об этом, только в каком это состоянии.
Хотел спросить, у вас возможен query decomposition? Одну часть запроса написал и используешь везде. Ведь вы знакомы с IQueryable и что с этим можно вытворять.
Согласен такая отдельная утилита была бы очень полезна.
Например, я в процессе ускорения работы базы. Добавляю прямо в нее индексы, новые колонки, таблицы. И тут ты понимаешь что все это надо повторить в миграции — я бы прыгал от счастья если бы мне сгенерили миграцию по diff, которую я бы ревьювнул и добавил в проект.
Наверное я вас не отговорю если скажу, что код этих расширений ужасен и иногда опасен.
Я провел некоторое время с их кодом, разбираясь как они интегрировались. Это печаль. К сожалению они уже закрыли сурцы, придется им дальше платить без оглядки.
Но если, все же, если я смог закласть зерна сомнения, попробуйте нашу итеграцию linq2db.EntityFrameworkCore. К релизу осталось пару дней, но пробовать можно уже.
Идея в том, что нет однозначного отображения из LINQ в SQL

То что MS библиотеки его не сделали, не значит что это невозможно. В LinqToDB, как раз делается все, чтобы вы могли написать практически любой запрос на LINQ. Недавно пал CTE.
Я не специалист в EF, но насколько я знаю, прочитав их спецификацию, использование IgnoreQueryFilters отрубает фильтры во всем запросе. Поправьте меня если я не прав.
Для меня это выглядит как: мы вам даем сомнительную возможность отфильтровать гарантировано, но оставили лазейку. И кто-то таки выстрелит себе в ногу.

Как насчет нарезать доступ контролировано, я про свой сампл Context.GetPermittedOrders(BusinessRole.Manager)? Ваше же решение режет энтити на корню.

Имея большой опыт разработки, дам простой совет: чем проще, тем лучше. И в поддержке и в выявлении багов. Как раз разбираюсь с одним багом, который неявно вытекает из-за использования сомнительного решения по трансформациии дерева выражений перед отправкой его Query Provider. До сих пор теряюсь в догадках — зачем! Чем меньше динамики, тем приложение стабильнее.
Найти в каком месте фильтр был отключен для специфического DbSet.

Information

Rating
Does not participate
Registered
Activity