Pull to refresh

Comments 11

Если вы знакомы с LISP, например, то там есть механизм цитирования, который позволяет код интерпретировать как структуру данных, но в .NET такого нет.

В .NET такое есть. А в C# — нет.


Code Quotations

Спасибо за то что поправили. Я конечно имел в виду C#. В F# ещё и провайдеры типов и проблематика EF в нем не так актуальна.

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

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

Пост хорош, дает стимул мозгу и позволяет продумать стратегию как работать с linq запросами. Это деревья и надо понимать почему. Шишки в этом набиты серьезные, зато теперь такие хелперы я пишу с первого раза, ну со второго ;)
Что именно «такое» делается в linq2db через ExpressionMethod?
Инлайнятся выражения. И много бойлерплейт кода забирается. Например (из реального пректа).

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) в фильтре или в проекции. И конечно же дальше уже лавинно можно в таких методах обращаться к другим таким же методам. Строятся хелперы и написание запроса превращается в легкую прогулку.

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

Хорошо, но как это поможет реализовать паттерн "спецификация"?

А эта штука тоже декомпилирует через GetIlAsByteArray?
В этой статье столько патернов накидано, за все я не говорил.

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

Для таких вещей я делаю просто 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);
}

Ну так и в EF делается точно так же. Если же вдруг становится нужно использовать именно паттерн «Спецификация» — то атрибут ExpressionMethod почему-то ничего не упрощает.

PS научитесь уже использовать кнопку «Ответить» вместо «Написать комментарий»
Нажимаю «ответить» всегда. Кто глючит не знаю.

Встречный вопрос, вы в своих спецификациях ногу не сломали? Долго ли ищите корень зла при правке багов?
Sign up to leave a comment.