Re[27]: Давайте поговорим о c# 3.0
От: MxKazan Португалия  
Дата: 22.09.08 14:31
Оценка:
Здравствуйте, Lloyd, Вы писали:

L>Здравствуйте, MxKazan, Вы писали:


L>>>Предположим, что у нас есть класс "Группа", у которой есть свойство-коллекция "Студенты". Что должно произойти с содержимым этой поллекции при удалении студента не напрямую, а опосредованно, через delete-запрос?


MK>>Это вполне можно оставить на разработчика. Если его будет интересовать состояние коллекции "Студенты", то он ее перечитает.


L>Как? И как он узнает, что именно надо перечитать?


Эээ... а что, человек работает с БД не зная о ёё структуре?
Re[28]: Давайте поговорим о c# 3.0
От: Lloyd Россия  
Дата: 22.09.08 14:34
Оценка:
Здравствуйте, MxKazan, Вы писали:

L>>>>Предположим, что у нас есть класс "Группа", у которой есть свойство-коллекция "Студенты". Что должно произойти с содержимым этой поллекции при удалении студента не напрямую, а опосредованно, через delete-запрос?


MK>>>Это вполне можно оставить на разработчика. Если его будет интересовать состояние коллекции "Студенты", то он ее перечитает.


L>>Как? И как он узнает, что именно надо перечитать?


MK>Эээ... а что, человек работает с БД не зная о ёё структуре?


Не о стурктуре речь. Даже если предположить, что он ее знает, не факт, что он знает о всех загруженных в данный момент в память "Группах".
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Re[29]: Давайте поговорим о c# 3.0
От: MxKazan Португалия  
Дата: 22.09.08 14:48
Оценка:
Здравствуйте, Lloyd, Вы писали:

L>Здравствуйте, MxKazan, Вы писали:


L>>>>>Предположим, что у нас есть класс "Группа", у которой есть свойство-коллекция "Студенты". Что должно произойти с содержимым этой поллекции при удалении студента не напрямую, а опосредованно, через delete-запрос?


MK>>>>Это вполне можно оставить на разработчика. Если его будет интересовать состояние коллекции "Студенты", то он ее перечитает.


L>>>Как? И как он узнает, что именно надо перечитать?


MK>>Эээ... а что, человек работает с БД не зная о ёё структуре?


L>Не о стурктуре речь. Даже если предположить, что он ее знает, не факт, что он знает о всех загруженных в данный момент в память "Группах".


Ну это уже скорее вопросы проектирования. Удалять что-то, не понимая к чему это может привести — неправильный метод. Такой случай я и не рассматриваю.
Re[25]: Давайте поговорим о c# 3.0
От: Константин Л. Франция  
Дата: 22.09.08 14:59
Оценка:
Здравствуйте, Lloyd, Вы писали:

L>Здравствуйте, Sinclair, Вы писали:


S>>Здравствуйте, Lloyd, Вы писали:


L>>>А как определить, что конкретный петя подпадает под это условие? Что если список оценок на клиента еще не загружен?

S>>Не надо ничего загружать. Нужно просто сконвертировать linq запрос в sql запрос и передать на сервер для выполнения.

L>Предположим, что у нас есть класс "Группа", у которой есть свойство-коллекция "Студенты". Что должно произойти с содержимым этой поллекции при удалении студента не напрямую, а опосредованно, через delete-запрос?


гм. то же, что в случае когда эта коллекция есть в кеше другого клиента. ты никогда не узнаешь, актуальные ли данные у тебя в данный момент. они теряют актуальность на момент, когда выплевываются из базы (читай заканчивается транзакция)
Re[30]: Давайте поговорим о c# 3.0
От: Lloyd Россия  
Дата: 22.09.08 14:59
Оценка:
Здравствуйте, MxKazan, Вы писали:

L>>Не о стурктуре речь. Даже если предположить, что он ее знает, не факт, что он знает о всех загруженных в данный момент в память "Группах".


MK>Ну это уже скорее вопросы проектирования. Удалять что-то, не понимая к чему это может привести — неправильный метод.


А если удаляя что-то мы всегда должны помнить, на что это может повлиять, то получаем высокую связность. Что тоже не хорошо.
Так что, как ни крути, а ничего хорошего от добавления удаления без предварительно загрузки в память — не получается.
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Re[31]: Давайте поговорим о c# 3.0
От: MxKazan Португалия  
Дата: 22.09.08 15:09
Оценка:
Здравствуйте, Lloyd, Вы писали:

L>Здравствуйте, MxKazan, Вы писали:


L>>>Не о стурктуре речь. Даже если предположить, что он ее знает, не факт, что он знает о всех загруженных в данный момент в память "Группах".


MK>>Ну это уже скорее вопросы проектирования. Удалять что-то, не понимая к чему это может привести — неправильный метод.


L>А если удаляя что-то мы всегда должны помнить, на что это может повлиять, то получаем высокую связность. Что тоже не хорошо.

L>Так что, как ни крути, а ничего хорошего от добавления удаления без предварительно загрузки в память — не получается.

Ну собственно, вынуждая нас запрашивать из БД, то что мы и без того хотим удалить, Linq данную проблему никак не решает, потому что сюда
Автор: Константин Л.
Дата: 22.09.08
.
Re[30]: Давайте поговорим о c# 3.0
От: GlebZ Россия  
Дата: 22.09.08 15:10
Оценка:
Здравствуйте, MxKazan, Вы писали:

MK>Ну это уже скорее вопросы проектирования. Удалять что-то, не понимая к чему это может привести — неправильный метод. Такой случай я и не рассматриваю.

Здря. Linq предоставляет возможности по декомпозиции. А это значит что часть запросов или даже часть запроса может быть перенесена в другой кусок кода. Не нужно в голове держать полную последовательность действий.
Re[32]: Давайте поговорим о c# 3.0
От: Lloyd Россия  
Дата: 22.09.08 15:13
Оценка:
Здравствуйте, MxKazan, Вы писали:

L>>А если удаляя что-то мы всегда должны помнить, на что это может повлиять, то получаем высокую связность. Что тоже не хорошо.

L>>Так что, как ни крути, а ничего хорошего от добавления удаления без предварительно загрузки в память — не получается.

MK>Ну собственно, вынуждая нас запрашивать из БД, то что мы и без того хотим удалить, Linq данную проблему никак не решает, потому что сюда
Автор: Константин Л.
Дата: 22.09.08
.


Есть такое. Но если с рассогласованностью кэшей у разных клиентов еще как-то можно смириться, то с рассогласованностью с самим собой — это уже по-моему чрезчур.
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Re[32]: Давайте поговорим о c# 3.0
От: GlebZ Россия  
Дата: 22.09.08 15:24
Оценка:
Здравствуйте, MxKazan, Вы писали:

MK>Ну собственно, вынуждая нас запрашивать из БД, то что мы и без того хотим удалить, Linq данную проблему никак не решает, потому что сюда
Автор: Константин Л.
Дата: 22.09.08
.

Почему не решает? Вполне решает. Просто тут важны приоритеты. Транзакция которая закончилась неуспешно, и не смогла перевести базу данных в несогласованное состояние — это почти не зло. Зло — это когда губят базу данных. Если мы выходим за пределы транзакции, то это действительно нужно делать осторожно. Глобальный кэш — это хорошее средство для того чтобы ее загубить. Но если ты не выходишь за пределы транзакции, используешь только те данные которые в данной транзакции получены и не изменены другой транзакцией до фиксации (что опасно в кэше), то проблемы как таковой — нет. Средств для обеспечения согласованности, тот же DbContext — вполне достаточны.
Re[10]: Давайте поговорим о c# 3.0
От: IT Россия linq2db.com
Дата: 22.09.08 15:27
Оценка: 101 (10) +4
Здравствуйте, MxKazan, Вы писали:

IT>>В некотором смысле первый. Дело в том, что преобразованием имени класса в имя поля теперь занимается сам компилятор. Ранее это был ручной или генерируемый код.

MK>А какая в сущности разница?

Комрилятор знает больше. Сгенерированная строковая константа для компилятора всё так же остаётся константой. А поле/свойство класса — это ещё и принадлежность к определённому классу. В принципе, precompile-time генератция может многое, но у неё свои козявки. Идеал же вообще ещё не достигнут, но уже возможен. Так, например, уже сегодня вполне возможно на Немерле генерировать необходимую метаинформацию непосредственно из БД в компайл-тайм

MK>Намёк ясен. Но он не совсем применим к Linq-To-Sql, уж слишком специфично, я написал чего не хватает. Видно и Microsoft это понимает, потому и есть Entity Framework. А проблема с DELETE похоже не имеет простого решения.


По мне, так EF — это чистый маркетинг. Наш ответ Хайберлену. Есть же в конце концов и другие невостребованные технологии у MS вроде того же WWF. Будет ещё одна.

MK>Ну вот, например, мне хотелось обновлять объекты в БД так, чтобы генерируемый Sql запрос не проверял изменение остальных полей (имеется ввиду concurrency). Приходилось ручками проставлять почти всем полям класса UpdateCheck в Never. Поменял поле, перегенерил класс и опять давай проставлять. Справедливости ради скажу, это скорее следует отнести к недостаткам Студии.


То о чём ты говоришь если это так, то это ошибки в дизайне. Я не хочу, чтобы компьютер за меня думал. Машина не должна думать, машина должна ездить. Куда скажу, туда и поехала. Тут в соседней ветке об этом уже на 400 сообщений нафлеймили, доказывая, что в хайбернейте LL это очень полезно. Вот такими спецэфектами потом приходится расплачиваться.

IT>>Linq 2 Objects внёс декларативность. Т.е. теперь я пишу что я хочу получить, а не как. В результате вместо кучи циклов с перебором списков и словарей у меня декларативная конструкция.

MK>Это понятно, про ФП я читал. Но не очень понятно в чем конкретная новизна по памяти? Речь о локальности данных?

О декларативности работы с данными. Давай рассмотрим пример, может быть так понятней будет. Пример возьмём не очень сложный, но и не самый простой, т.к. на простых примерах вся мощь линка не так проявляется.

Возьмём финансовую задачку. Допустим у нас есть провайдеры, которые тратят бабло и есть получатели, на которых это бабло списывается. С провайдеров деньги списываются через аккаунты в соответствии с определёнными процентами. Например, провайдер '1111' списывает 20% на аккаунт 'AAAA' и 80% на аккаунт 'BBBB'. Получатели получают свою долю тоже через аккаунты, по такому же принципу, т.е., например, получатель '8888' получает 40% с аккаунта 'AAAA' и 60% с аккаунта 'BBBB'. Наша задача получить массив процентов, в котором будет указано, что провайдер '1111' списывает через аккаунт 'AAAA' столько-то процентов на '8888'.

Ниже приведён код. Метод CalcPercents делает эту работу с помощью linq, метод CalcPercents2 в исполнении C# 2.0.

using System;
using System.Linq;
using System.Collections.Generic;

namespace ConsoleApplication
{
    class Program
    {
        class ProvidingVolume
        {
            public string Provider;
            public string Account;
            public double Volume;
        }

        class ReceivingVolume
        {
            public string Receiver;
            public string Account;
            public double Volume;
        }

        class Percent
        {
            public string Provider;
            public string Receiver;
            public string Account;
            public double Value;
        }

        static Dictionary<string, List<Percent>> CalcPercents(
            ProvidingVolume[] providingVolumes, ReceivingVolume[] receivingVolumes)
        {
            var percents = 
                from percent in
                    from prov in
                        from p in providingVolumes
                        group p by p.Provider into pg
                        let total = pg.Sum(v => v.Volume)
                        from pp in pg
                        select new { pp, total }
                    join rec in
                        from r in receivingVolumes
                        group r by r.Account into rg
                        let total = rg.Sum(v => v.Volume)
                        from rr in rg
                        select new { rr, total }
                    on prov.pp.Account equals rec.rr.Account
                    select new Percent
                    {
                        Provider = prov.pp.Provider,
                        Receiver = rec.rr.Receiver,
                        Account  = prov.pp.Account,
                        Value    = prov.pp.Volume / prov.total * rec.rr.Volume / rec.total
                    }
                group percent by percent.Provider;

            return percents.ToDictionary(p => p.Key, p => p.ToList());
        }

        static Dictionary<string, List<Percent>> CalcPercents2(
            ProvidingVolume[] providingVolumes, ReceivingVolume[] receivingVolumes)
        {
            Dictionary<string, List<ProvidingVolume>> providingGroup = new Dictionary<string,List<ProvidingVolume>>();

            foreach (ProvidingVolume pv in providingVolumes)
            {
                List<ProvidingVolume> p;

                if (!providingGroup.TryGetValue(pv.Provider, out p))
                {
                    p = new List<ProvidingVolume>();
                    providingGroup[pv.Provider] = p;
                }

                p.Add(pv);
            }

            Dictionary<string, List<ReceivingVolume>> receivingGroup = new Dictionary<string,List<ReceivingVolume>>();

            foreach (ReceivingVolume rv in receivingVolumes)
            {
                List<ReceivingVolume> r;

                if (!receivingGroup.TryGetValue(rv.Account, out r))
                {
                    r = new List<ReceivingVolume>();
                    receivingGroup[rv.Account] = r;
                }

                r.Add(rv);
            }

            Dictionary<string, double> receivingSum = new Dictionary<string,double>();

            foreach (List<ReceivingVolume> list in receivingGroup.Values)
            {
                double sum = 0;

                foreach (ReceivingVolume rv in list)
                    sum += rv.Volume;

                receivingSum[list[0].Account] = sum;
            }

            Dictionary<string, List<Percent>> percents = new Dictionary<string,List<Percent>>();

            foreach (List<ProvidingVolume> list in providingGroup.Values)
            {
                double sum = 0;

                foreach (ProvidingVolume pv in list)
                    sum += pv.Volume;

                foreach (ProvidingVolume pv in list)
                {
                    List<ReceivingVolume> rv;

                    if (receivingGroup.TryGetValue(pv.Account, out rv))
                    {
                        foreach (ReceivingVolume r in rv)
                        {
                            Percent percent = new Percent();

                            percent.Provider = pv.Provider;
                            percent.Receiver = r.Receiver;
                            percent.Account  = pv.Account;
                            percent.Value    = pv.Volume / sum * r.Volume / receivingSum[r.Account];

                            List<Percent> ps;

                            if (!percents.TryGetValue(percent.Provider, out ps))
                            {
                                ps = new List<Percent>();
                                percents.Add(percent.Provider, ps);
                            }

                            ps.Add(percent);
                        }
                    }
                }
            }

            return percents;
        }

        static void Main(string[] args)
        {
            var providingVolums = new []
            {
                new ProvidingVolume { Provider = "1111", Account = "AAAA", Volume = 20 },
                new ProvidingVolume { Provider = "1111", Account = "BBBB", Volume = 80 },
                new ProvidingVolume { Provider = "2222", Account = "AAAA", Volume = 30 },
                new ProvidingVolume { Provider = "2222", Account = "BBBB", Volume = 70 },
            };

            var receivingVolumes = new []
            {
                new ReceivingVolume { Receiver = "8888", Account = "AAAA", Volume = 40 },
                new ReceivingVolume { Receiver = "8888", Account = "BBBB", Volume = 60 },
                new ReceivingVolume { Receiver = "9999", Account = "AAAA", Volume = 50 },
                new ReceivingVolume { Receiver = "9999", Account = "BBBB", Volume = 50 },
            };

            var percents = CalcPercents(providingVolums, receivingVolumes);

            foreach (var ps in percents.Values)
                foreach (var p in ps)
                    Console.WriteLine("{0} {1} {2} {3}", p.Provider, p.Receiver, p.Account, p.Value);

            percents = CalcPercents2(providingVolums, receivingVolumes);

            foreach (var ps in percents.Values)
                foreach (var p in ps)
                    Console.WriteLine("{0} {1} {2} {3}", p.Provider, p.Receiver, p.Account, p.Value);
        }
    }
}

output:
1111 8888 AAAA 0.0888888888888889
1111 9999 AAAA 0.111111111111111
1111 8888 BBBB 0.436363636363636
1111 9999 BBBB 0.363636363636364
2222 8888 AAAA 0.133333333333333
2222 9999 AAAA 0.166666666666667
2222 8888 BBBB 0.381818181818182
2222 9999 BBBB 0.318181818181818

Обрати внимание, кода на линке в 3 раза меньше и он декларативен, в отличии от императивщины на C# 2.0. А если учесть, что таких вычислений у меня в коде пачками, то выгода linq более чем очевидна.

MK>Но вообще, IT, я бы хотел еще раз обозначить, что я принципе не против Linq. Хотелось бы просто понимать реальную необходимость этого, реальные плюсы, а не просто как "игрушка для этюдов". Разве это есть гуд, требовать "что", не понимая "как"?


Но ты же не говоришь SQL серверу как именно выполнять запросы? Ты говоришь, хочу то-то и то-то, а он уже сам читает с диска или из кеша, оптимизирует запросы и занимается прочими 'как'.
Неясность изложения обычно происходит от путаницы в мыслях.
Если нам не помогут, то мы тоже никого не пощадим.
Re[33]: Давайте поговорим о c# 3.0
От: Константин Л. Франция  
Дата: 22.09.08 16:13
Оценка:
Здравствуйте, Lloyd, Вы писали:

[]

L>Есть такое. Но если с рассогласованностью кэшей у разных клиентов еще как-то можно смириться, то с рассогласованностью с самим собой — это уже по-моему чрезчур.


но тогда, по твоим словам, проблема не решаема
Re[34]: Давайте поговорим о c# 3.0
От: Lloyd Россия  
Дата: 22.09.08 16:14
Оценка:
Здравствуйте, Константин Л., Вы писали:

L>>Есть такое. Но если с рассогласованностью кэшей у разных клиентов еще как-то можно смириться, то с рассогласованностью с самим собой — это уже по-моему чрезчур.


КЛ>но тогда, по твоим словам, проблема не решаема


которая из?
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Re[35]: Давайте поговорим о c# 3.0
От: Константин Л. Франция  
Дата: 22.09.08 16:20
Оценка:
Здравствуйте, Lloyd, Вы писали:

L>Здравствуйте, Константин Л., Вы писали:


L>>>Есть такое. Но если с рассогласованностью кэшей у разных клиентов еще как-то можно смириться, то с рассогласованностью с самим собой — это уже по-моему чрезчур.


КЛ>>но тогда, по твоим словам, проблема не решаема


L>которая из?


1. использовать линк
2. грохать каким-то образом объекты
3. "не поломать" загруженные объекты
Re[36]: Давайте поговорим о c# 3.0
От: Lloyd Россия  
Дата: 22.09.08 16:22
Оценка:
Здравствуйте, Константин Л., Вы писали:

L>>>>Есть такое. Но если с рассогласованностью кэшей у разных клиентов еще как-то можно смириться, то с рассогласованностью с самим собой — это уже по-моему чрезчур.


КЛ>>>но тогда, по твоим словам, проблема не решаема


L>>которая из?


КЛ>1. использовать линк

КЛ>2. грохать каким-то образом объекты
КЛ>3. "не поломать" загруженные объекты

Выходит что так.
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Re[37]: Давайте поговорим о c# 3.0
От: Константин Л. Франция  
Дата: 22.09.08 16:25
Оценка:
Здравствуйте, Lloyd, Вы писали:

L>Здравствуйте, Константин Л., Вы писали:


L>>>>>Есть такое. Но если с рассогласованностью кэшей у разных клиентов еще как-то можно смириться, то с рассогласованностью с самим собой — это уже по-моему чрезчур.


КЛ>>>>но тогда, по твоим словам, проблема не решаема


L>>>которая из?


КЛ>>1. использовать линк

КЛ>>2. грохать каким-то образом объекты
КЛ>>3. "не поломать" загруженные объекты

L>Выходит что так.


не может быть

а что там у нас с identity? есть что почитать по Linq internals?
Re[38]: Давайте поговорим о c# 3.0
От: Lloyd Россия  
Дата: 22.09.08 16:26
Оценка:
Здравствуйте, Константин Л., Вы писали:

L>>Выходит что так.


КЛ>не может быть


КЛ>а что там у нас с identity? есть что почитать по Linq internals?


да нет там никаких особо internals. linq прост как пробка.
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Re[39]: Давайте поговорим о c# 3.0
От: Константин Л. Франция  
Дата: 22.09.08 16:34
Оценка:
Здравствуйте, Lloyd, Вы писали:

L>Здравствуйте, Константин Л., Вы писали:


L>>>Выходит что так.


КЛ>>не может быть


КЛ>>а что там у нас с identity? есть что почитать по Linq internals?


L>да нет там никаких особо internals. linq прост как пробка.


ну так с identity то что?
Re[40]: Давайте поговорим о c# 3.0
От: Lloyd Россия  
Дата: 22.09.08 16:48
Оценка:
Здравствуйте, Константин Л., Вы писали:

КЛ>>>не может быть


КЛ>>>а что там у нас с identity? есть что почитать по Linq internals?


L>>да нет там никаких особо internals. linq прост как пробка.


КЛ>ну так с identity то что?


c identity все хорошо. в чем вопрос-то?
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Re[41]: Давайте поговорим о c# 3.0
От: Константин Л. Франция  
Дата: 22.09.08 16:55
Оценка:
Здравствуйте, Lloyd, Вы писали:

[]

что в линке под айдентити подразумевается
Re[6]: Давайте поговорим о c# 3.0
От: Roman Odaisky Украина  
Дата: 22.09.08 21:08
Оценка:
Здравствуйте, nikov, Вы писали:

RO>>Какая именно?

RO>>Он написал не одну, и российские издательства использовали разные написания.

N>На какую книгу ссылаешься, из той книги вариант написания фамилии автора и надо брать для ссылки.


А если я хочу сказать: «Некто Тр___сен заявляет, будто неплохо разбирается в .NET»?
До последнего не верил в пирамиду Лебедева.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.