Здравствуйте, yuriylsh, Вы писали:
Y> Значит, говоришь, отказ от юнит-тестов делает код живым, развивающимся и легкомодифицируемым?
Если кто то не согласен с тем, что юнит-тесты в массовых количествах это всегда очень хорошо, это совсем не означает, что он утверждает, что юнит-тесты это всегда плохо.
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Если кто то не согласен с тем, что юнит-тесты в массовых количествах это всегда очень хорошо, это совсем не означает, что он утверждает, что юнит-тесты это всегда плохо.
Я отвечал на вполне конкретное заявление и iHateLogins вполне однозначно сказал то что сказал. Там не было ничего ни про массовые колличества ни про всегда плохо.
Инструменты на то и нужны, чтобы делать жизнь проще. Если вы сначала стреляете себе в ногу (юнит-тесты), ползёте с черепашьей скоростью, утверждая, что зато "так надёжнее" — то это ваши проблемы и проблемы ваших заказчиков. Рано или поздно они не оценят такой, хм, производительности, и выберут того, кто делает свою работу быстрее. Пусть код не будет покрыт юнит-тестами и API зацементирован этими самыми тестами, зато он будет живой, развивающийся и легкомодифицируемый.
Luck in life always exists in the form of an abstract class that cannot be instantiated directly and needs to be inherited by hard work and dedication.
Здравствуйте, Ikemefula, Вы писали:
HL>>Имхо, всё это — естественная реакция. ИТ так далеко шагнуло за последние 10 лет, что, если писать эффективные программы ЭФФЕКТИВНО, толпу всякой около-итной шушеры придётся гнать взашей. Вот они и держутся, как могут. И начинается... простейшие сайтики становятся сложнейшими инжереными проектами с командой поддержки в 20-30 человек, вместо простых селектов в базе накручиваются просто МЕГАТОННЫ всякого водопроводного (plumbing) говно-кода, фреймворки над фреймворками... а дальше начинается... добавить колонку? СЛОЖНЕЙШАЯ ЗАДАЧА! Переработать модуль? Да проще новый написать, желательно даже не модуль, а проект с нуля, потому что разобраться в тоннах запутанного кода с десятками тысяч никому не нужных юнит-тестов становится просто невозможно.
I>Я немного не понял, что ты имел ввиду про селекты. Как раз накидав всяких селектов получается геморрой — надо добавить колонку таблицу и для этого приходтся перелопачивать селекты.
При добавлении колонки в таблицу все существующие селекты будут работать без проблем, зачем их перелопачивать?
Здравствуйте, Ночной Смотрящий, Вы писали:
L>>Мой опыт показывает, что с тестами скорость разработки увеличивается раза в два. НС>А мой — уменьшается в два раза. Мое имхо против твоего имха?
Референсы будут? У меня — без проблем.
Здравствуйте, gandjustas, Вы писали:
G>Здравствуйте, _d_m_, Вы писали:
___>>Здравствуйте, gandjustas, Вы писали:
G>>>>>>>Оптимизатор у MS SQL достаточно умный чтобы по запросу сгенерированному с помощью Linq построить хороший план.
L>>>>>>И каким же образом он узнает, что запрос сгенерирован LINQ-ом, а не руками?
G>>>>>Никак, а оно ему надо?
___>>>>Ну ты же сказал, что SQL запросы от линка гораздо быстрее: т.к. индексы, кэширование в БД, оптимизатор умный. G>>>Ссылку.
___>>А что по ветке чуть вверх подняться не судьба? ___>>http://rsdn.ru/forum/flame.comp/3445983.1.aspx
G>Читаете через слово? G>Вот проведите эксперимент. Напишите сложный linq запрос и его аналог в sql.
G>>>У меня был один запрос, который давал SQL примерно на два листа A4, при этом он работал достаточно быстро. G>>>Такой запрос я бы просто физически не нарисовал руками, а если бы даже наприсовал, то замучался бы его поддерживать. ___>>Я рисую, поддерживаемость отличная. G>Мне тебя жаль.
Хм. Май янг френд. Шутка конечно.
Вот когда будешь SQL программером, тогда я посмотрю кто кого будет жалеть.
Хочу такого же на линк:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER proc [dbo].[ОтчетОстаткиТоваров1](
@СкладыУчастникиXML xml,
@НаДату datetime = null,
@Товар char(10) = null,
@ГруппыТоваровXML xml = null,
@ТипУчета tinyint = null,
@флСортПоГруппам bit = 0
)
--# with encryptionas begin
set nocount on;
set transaction isolation level read committed;
-- Обработка параметровif @НаДату is null
set @НаДату = getdate();
-- Получим флаги разрешения просмотра ценdeclare @флРасхЦена tinyint, @флПрихЦена tinyint;
select
@флРасхЦена = флРасхЦена,
@флПрихЦена = флПрихЦена
from
dbo.Пользователи
where
Логин = system_user
;
-- Обработка товаров и группdeclare @ВеткаГруппТоваров table(
Группа char(10) primary key
);
if @Товар is not null
insert
@ВеткаГруппТоваров
select
КодРодителя
from
dbo.пТовары
where
Код = @Товар
;
else if @ГруппыТоваровXML is null
insert
@ВеткаГруппТоваров
select
Код
from
dbo.пТоварыГруппы
;
else
with
РОТВ as(
select
тг.Код
from
dbo.пТоварыГруппы тг
inner join
(select
Гр.value('@Код', 'char(10)') Группа
from
@ГруппыТоваровXML.nodes('/root/Группа') as T(Гр)
) г
on
тг.Код = г.Группа
union all
select
тг1.Код
from
dbo.пТоварыГруппы тг1
inner join
РОТВ в
on
тг1.КодРодителя = в.Код
)
insert
@ВеткаГруппТоваров
select distinct
Код
from
РОТВ
;
-- Обработка складов-участниковdeclare @тСкладыУчастники table(
Склад char(10) primary key
);
insert
@тСкладыУчастники
select
Ск.value('@Код', 'char(10)') Склад
from
@СкладыУчастникиXML.nodes('/root/Склад') as T(Ск)
;
-- Проверка RLSif exists(
select
null
from
@тСкладыУчастники су
where
not exists(
select
null
from
dbo.пСклады as с
where
су.Склад = с.Код
)
) begin
raiserror('Нарушение доступа RLS', 16, 1);
return;
end;
declare @Год int, @Квартал int, @ТочкаРаздела datetime;
set @Год = datepart(year, @НаДату) - 1900;
set @Квартал = datepart(quarter, @НаДату) - 1;
set @ТочкаРаздела = dateadd(quarter, @Квартал + @Год * 4, 0);
set @Квартал = (@Год + 1900) * 4 + @Квартал;
-- Возвращаем результат
-- Получим склады участникиselect
с.Код as Склад_Код,
с.Наименование as Склад
from
@тСкладыУчастники су
inner join
dbo.Склады с
on
су.Склад = с.Код
order by
с.Наименование
;
-- Возвращаем основной результатselect
ДляСорт.Товар_Код,
ДляСорт.Товар,
ДляСорт.ПолныйПутьГруппы,
ДляСорт.Склад_Код,
ДляСорт.Остаток,
dbo.УдобочитаемаяПартия(ДляСорт.ИдТипаДокаПартии, ДляСорт.КодДокаПартии, ДляСорт.НомерПартии, ' ') as Партия,
dbo.ПолучитьБазовуюЕдиницу(ДляСорт.Товар_Код) as Единица,
case @флПрихЦена
when 1 then ДляСорт.Себестоимость
end as Себестоимость,
case @флПрихЦена
when 1 then dbo.ТоварЗакупЦена_NonRLS(ДляСорт.Товар_Код, @НаДату)
end as ПрихЦена,
case @флРасхЦена
when 1 then dbo.ТоварЦена_NonRLS(ДляСорт.Товар_Код, @НаДату, default)
end as ПродЦена,
(select
isnull(sum(Резерв), 0.0)
from
dbo.РезервыТоваров as рт
where
рт.Товар = ДляСорт.Товар_Код and
рт.Склад = ДляСорт.Склад_Код
) as Резерв
from
(select
ТО.Товар_Код,
т.Наименование as Товар,
dbo.ф_ТоварыГруппыПолныйПуть(т.КодРодителя) as ПолныйПутьГруппы,
ТО.Склад_Код,
ТО.Остаток,
ТО.Себестоимость,
ТО.ИдТипаДокаПартии,
ТО.КодДокаПартии,
ТО.НомерПартии
from
(select
isnull(Гпдт.Склад, Гдт.Склад) as Склад_Код,
isnull(Гпдт.Товар, Гдт.Товар) as Товар_Код,
sum(isnull(Гпдт.ДвижениеОстатка, 0.0) + isnull(Гдт.ДвижениеОстатка, 0.0)) as Остаток,
sum(isnull(Гпдт.ДвижениеСебест, 0.0) + isnull(Гдт.ДвижениеСебест, 0.0)) as Себестоимость,
isnull(Гпдт.ИдТипаДокаПартии, Гдт.ИдТипаДокаПартии) as ИдТипаДокаПартии,
isnull(Гпдт.КодДокаПартии, Гдт.КодДокаПартии) as КодДокаПартии,
isnull(Гпдт.НомерПартии, Гдт.НомерПартии) as НомерПартии
from
(select
пдт.Склад,
пдт.Товар,
пдт.ИдТипаДокаПартии,
пдт.КодДокаПартии,
пдт.НомерПартии,
sum(пдт.ДвижениеОстатка) as ДвижениеОстатка,
sum(пдт.ДвижениеСебест) as ДвижениеСебест
from
dbo.пГДвиженияТоваров as пдт with(noexpand)
where
exists(
select
null
from
@тСкладыУчастники с
where
с.Склад = пдт.Склад
) and
exists(
select
null
from
dbo.ТоварыГруппыММ гмм
inner join
@ВеткаГруппТоваров вгт
on
гмм.Группа = вгт.Группа
where
пдт.Товар = гмм.Товар
) and
пдт.Квартал <= @Квартал and
(пдт.Товар = @Товар or @Товар is null)
group by
пдт.Склад,
пдт.Товар,
пдт.ИдТипаДокаПартии,
пдт.КодДокаПартии,
пдт.НомерПартии
) as Гпдт
full outer join
(select
дт.Склад,
дт.Товар,
дт.ИдТипаДокаПартии,
дт.КодДокаПартии,
дт.НомерПартии,
sum(дт.ДвижениеОстатка) as ДвижениеОстатка,
sum(дт.ДвижениеСебест) as ДвижениеСебест
from
dbo.ДвиженияТоваров as дт
where
exists(
select
null
from
@тСкладыУчастники с
where
с.Склад = дт.Склад
) and
exists(
select
null
from
dbo.ТоварыГруппыММ гмм
inner join
@ВеткаГруппТоваров вгт
on
гмм.Группа = вгт.Группа
where
дт.Товар = гмм.Товар
) and
дт.ТочкаВремени >= @ТочкаРаздела and
дт.ТочкаВремени < @НаДату and
(дт.Товар = @Товар or @Товар is null)
group by
дт.Склад,
дт.Товар,
дт.ИдТипаДокаПартии,
дт.КодДокаПартии,
дт.НомерПартии
) as Гдт
on
Гпдт.Товар = Гдт.Товар and
Гпдт.Склад = Гдт.Склад and
Гпдт.ИдТипаДокаПартии = Гдт.ИдТипаДокаПартии and
Гпдт.КодДокаПартии = Гдт.КодДокаПартии and
Гпдт.НомерПартии = Гдт.НомерПартии
group by
isnull(Гпдт.Товар, Гдт.Товар),
isnull(Гпдт.Склад, Гдт.Склад),
isnull(Гпдт.ИдТипаДокаПартии, Гдт.ИдТипаДокаПартии),
isnull(Гпдт.КодДокаПартии, Гдт.КодДокаПартии),
isnull(Гпдт.НомерПартии, Гдт.НомерПартии)
having
sum(isnull(Гпдт.ДвижениеОстатка, 0.0) + isnull(Гдт.ДвижениеОстатка, 0.0)) != 0.0
) as ТО
inner join
dbo.Товары as т
on
ТО.Товар_Код = т.Код
where
т.флУпрУчет = @ТипУчета or @ТипУчета is null
) as ДляСорт
order by
case @флСортПоГруппам
when 1 then rank() over(order by ДляСорт.ПолныйПутьГруппы, ДляСорт.Товар, ДляСорт.Склад_Код)
else rank() over(order by ДляСорт.Товар, ДляСорт.Склад_Код)
end
;
end
GO
GRANT EXECUTE ON [dbo].[ОтчетОстаткиТоваров1] TO [1 ОтчетОстаткиТоваров]
Здравствуйте, _d_m_, Вы писали:
___>Хм. Май янг френд. Шутка конечно. ___>Вот когда будешь SQL программером, тогда я посмотрю кто кого будет жалеть.
Не, я не буду sql-, или каким_то_другим- программером. Я стараюсь быть просто программистом, который для решения задач выбирает подходящее средство.
И мне всегда жаль будет sql-, или_еще_каких_то- программеров которые используя неподходящие средства пытаются скрестить ежа с ужом.
___>Хочу такого же на линк:
Опиши по-русски что код делает, а то реверсить такое желания нету.
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Здравствуйте, _d_m_, Вы писали:
___>>Ну дак я ему уже так толсто намекал. Хотелось бы узнать природу этого чуда.
НС>Природа этого чуда заключается в двух моментах НС>1) Генератор l2s знает об особенностях работы оптимизатора сиквела немножко больше среднего программиста. Я неоднократно наблюдал, когда текст запроса обсирался "спецами" по написанию рукопашных, а потом красивый рукопашный скрипт работал медленнее обосранного автоматического.
Только плюс линку. Но заниматься преждевременной оптимизацией — "красивый рукопашный скрипт" — зло. Запросы надо писать так, как-будто ничего не знаешь про работу движка СУБД. И только если есть проблемы с перфомансом — тогда надо взятся всерьез. Вот тогда рукопашный скрипт становится красивым.
НС>2) Генератор l2s при динамической сборке запроса может кардинально перекраивать структуру генерируемого скрипта в зависимости от небольших изменений в исходном linq запросе. Руками такое, конечно же, сделать можно, но для этого потребен спец экстра класса, и поддерживаемось этого чуда будет никакой.
Классно. Но это хак. Оптимизатор СУБД должен этим заниматься.
PS: Речь изначально шла не об этом. Сначала gandjustas ляпнул ерунду (или коряво выразился), которую всем понять было только как: кэширование и индексы работают только для линк-запросов.
Здравствуйте, gandjustas, Вы писали:
___>>Хм. Май янг френд. Шутка конечно. ___>>Вот когда будешь SQL программером, тогда я посмотрю кто кого будет жалеть. G>Не, я не буду sql-, или каким_то_другим- программером. Я стараюсь быть просто программистом, который для решения задач выбирает подходящее средство. G>И мне всегда жаль будет sql-, или_еще_каких_то- программеров которые используя неподходящие средства пытаются скрестить ежа с ужом.
На SQL вообще-то все серьёзные ERP системы написаны, а не на C#. Говорю это вам как человек, который программирует на C# со второй беты 1.0 и на SQL уже больше 10 лет. C# — это такой integration язык, на нём хорошо писать "прослойки". Для серьёзной работы с данными человечество не придумал ничего лучше (T|PL)-SQL, для вычислений — ASM/C/C++, для UI всё больше народу выбирает HTML/CSS или "голый" winapi. На C#-е лучше всего писать веб-приложения или какой-то integration layer, но не транзакции. Во всяком случае, не серьёзные транзакции.
___>>Хочу такого же на линк: G>Опиши по-русски что код делает, а то реверсить такое желания нету.
Код-то простой как три копейки, что там реверсить-то?
Здравствуйте, gandjustas, Вы писали:
G>Здравствуйте, _d_m_, Вы писали:
___>>Хм. Май янг френд. Шутка конечно. ___>>Вот когда будешь SQL программером, тогда я посмотрю кто кого будет жалеть. G>Не, я не буду sql-, или каким_то_другим- программером. Я стараюсь быть просто программистом, который для решения задач выбирает подходящее средство. G>И мне всегда жаль будет sql-, или_еще_каких_то- программеров которые используя неподходящие средства пытаются скрестить ежа с ужом.
То есть я пытаюсь скрестить ужа с ежом? На каком основании мне навешан этот ярлык?
___>>Хочу такого же на линк: G>Опиши по-русски что код делает, а то реверсить такое желания нету.
Мне тебя жалко Шутка.
Остатки товаров на определнный момент времени получает c фильтром по веткам дерева групп, с фильтром по складам, при необходимости сортирует в группах товаров. Средний слой затем может провести дополнительные группировки и развертки ака pivot. Вобщем это не задача для легковесной ORM ака linq.
Здравствуйте, _d_m_, Вы писали:
НС>>2) Генератор l2s при динамической сборке запроса может кардинально перекраивать структуру генерируемого скрипта в зависимости от небольших изменений в исходном linq запросе. Руками такое, конечно же, сделать можно, но для этого потребен спец экстра класса, и поддерживаемось этого чуда будет никакой.
___>Классно. Но это хак. Оптимизатор СУБД должен этим заниматься.
Ты не понял. В самом языке SQL есть ограничения, делающие его менее выразительным, по сравнению с C#, на котором работает Linq. Поэтому небольшие изменения в Linq погут порождать занчительные измения в sql.
Яркий пример такого — сравнение с null. В sql получается разный текст запроса если надо сравнить с NULL или с конкретным значением, а в linq это пишется одинаково.
___>PS: Речь изначально шла не об этом. Сначала gandjustas ляпнул ерунду (или коряво выразился), которую всем понять было только как: кэширование и индексы работают только для линк-запросов.
Это ты неправльно понял. Я же уже писал выше, что наибольший вклад в производительность запроса обычно вносят индексы. Опитмизатор в MS SQL достаточно умный чтобы сгенеренному linq запросу построить более-менее оптимальный план.
Здравствуйте, iHateLogins, Вы писали:
HL>Здравствуйте, gandjustas, Вы писали:
___>>>Хм. Май янг френд. Шутка конечно. ___>>>Вот когда будешь SQL программером, тогда я посмотрю кто кого будет жалеть. G>>Не, я не буду sql-, или каким_то_другим- программером. Я стараюсь быть просто программистом, который для решения задач выбирает подходящее средство. G>>И мне всегда жаль будет sql-, или_еще_каких_то- программеров которые используя неподходящие средства пытаются скрестить ежа с ужом.
HL>На SQL вообще-то все серьёзные ERP системы написаны, а не на C#. Говорю это вам как человек, который программирует на C# со второй беты 1.0 и на SQL уже больше 10 лет. C# — это такой integration язык, на нём хорошо писать "прослойки". Для серьёзной работы с данными человечество не придумал ничего лучше (T|PL)-SQL, для вычислений — ASM/C/C++, для UI всё больше народу выбирает HTML/CSS или "голый" winapi. На C#-е лучше всего писать веб-приложения или какой-то integration layer, но не транзакции. Во всяком случае, не серьёзные транзакции.
___>>>Хочу такого же на линк: G>>Опиши по-русски что код делает, а то реверсить такое желания нету. HL>Код-то простой как три копейки, что там реверсить-то?
Ну расскажи что он там делает
Здравствуйте, _d_m_, Вы писали: ___>Хм. Май янг френд. Шутка конечно. ___>Вот когда будешь SQL программером, тогда я посмотрю кто кого будет жалеть. ___>Хочу такого же на линк:
А что мешает? Такое же на линке обычно выглядит гораздо более внятно. И не требует, в частности, массовых манипуляций с временными таблицами.
Что там у вас за ужос с @ВеткаГруппТоваров?
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, _d_m_, Вы писали:
___>Здравствуйте, gandjustas, Вы писали:
G>>Здравствуйте, _d_m_, Вы писали:
___>>>Хм. Май янг френд. Шутка конечно. ___>>>Вот когда будешь SQL программером, тогда я посмотрю кто кого будет жалеть. G>>Не, я не буду sql-, или каким_то_другим- программером. Я стараюсь быть просто программистом, который для решения задач выбирает подходящее средство. G>>И мне всегда жаль будет sql-, или_еще_каких_то- программеров которые используя неподходящие средства пытаются скрестить ежа с ужом. ___>То есть я пытаюсь скрестить ужа с ежом? На каком основании мне навешан этот ярлык?
Нет, я не говорил конкретно про тебя.
Просто подход "я умею писать на SQL, поэтому все будут писать на SQL" неправильный.(вместо SQL можно подставить любой другой язык)
___>>>Хочу такого же на линк: G>>Опиши по-русски что код делает, а то реверсить такое желания нету.
___>Мне тебя жалко Шутка. ___>Остатки товаров на определнный момент времени получает c фильтром по веткам дерева групп, с фильтром по складам, при необходимости сортирует в группах товаров. Средний слой затем может провести дополнительные группировки и развертки ака pivot. Вобщем это не задача для легковесной ORM ака linq.
Ок, судя по описанию так:
var warehouses = //обработка xml с помощью XLinq для вытаскивания складовvar groups = //обработка xml с помощью XLinq для вытаскивания группvar q = from p in db.Products
where warehouses.Contains(p.Warehouse)
where groups.Contains(p.Groups)
select p;
if(/*необходимость*/)
{
q = q.OrderBy(p => p.Group);
}
Далее этот запрос попадает в верхний слой, там проводятся дополнительные группировки, а на уровне PL приводится все в читаемый вид.
Причем пока реально не понадобилось отображать данные, то лучше и не будет этот запрос выполняться.
ЗЫ. А вообще такие вещи лучше делать в OLAP, чтобы он аггрегаты по любым измерениям собирал, а потом быстро отдавал без мега-запросов.
Здравствуйте, gandjustas, Вы писали:
G>Причем пока реально не понадобилось отображать данные, то лучше и не будет этот запрос выполняться.
Выделенное слово попало сюда по ошибке
Здравствуйте, iHateLogins, Вы писали:
I>>Я немного не понял, что ты имел ввиду про селекты. Как раз накидав всяких селектов получается геморрой — надо добавить колонку таблицу и для этого приходтся перелопачивать селекты.
HL>При добавлении колонки в таблицу все существующие селекты будут работать без проблем, зачем их перелопачивать?
А колонку ты зачем добавлял ? Просто что бы в базе побыла ?
Здравствуйте, gandjustas, Вы писали:
G>Здравствуйте, _d_m_, Вы писали:
НС>>>2) Генератор l2s при динамической сборке запроса может кардинально перекраивать структуру генерируемого скрипта в зависимости от небольших изменений в исходном linq запросе. Руками такое, конечно же, сделать можно, но для этого потребен спец экстра класса, и поддерживаемось этого чуда будет никакой.
___>>Классно. Но это хак. Оптимизатор СУБД должен этим заниматься. G>Ты не понял. В самом языке SQL есть ограничения, делающие его менее выразительным, по сравнению с C#, на котором работает Linq. Поэтому небольшие изменения в Linq погут порождать занчительные измения в sql. G>Яркий пример такого — сравнение с null. В sql получается разный текст запроса если надо сравнить с NULL или с конкретным значением, а в linq это пишется одинаково.
Эээ нет. null — это особая тема. Опять не умеешь готовить. Это не недостаток SQL — это совсем другое.
___>>PS: Речь изначально шла не об этом. Сначала gandjustas ляпнул ерунду (или коряво выразился), которую всем понять было только как: кэширование и индексы работают только для линк-запросов. G>Это ты неправльно понял. Я же уже писал выше, что наибольший вклад в производительность запроса обычно вносят индексы. Опитмизатор в MS SQL достаточно умный чтобы сгенеренному linq запросу построить более-менее оптимальный план.
Я же тебе говорю, что по любому SQL запросу оптимизатор строит самый оптимальный план.
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Здравствуйте, gandjustas, Вы писали:
G>>Мда... понимания ноль
НС>Любимый аргумент религиозных фанатиков.
начники пишут также, справедливости ради уточню