Re[10]: Некоторые мысли о LINQ
От: VladD2 Российская Империя www.nemerle.org
Дата: 13.01.09 07:26
Оценка:
Здравствуйте, Tissot, Вы писали:

T>А почему Axapta не является крупной системой?


А как ты думаешь с использованием каких подходов написана Axapta ?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: Некоторые мысли о LINQ
От: Tissot Россия  
Дата: 13.01.09 08:53
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Да, не плохо. Но в данном случае речь не о нем.


Ты не успел. Я уже смирился с попыткой что-либо доказать.
С "unit of work" подходом я работал и достаточно много. С ER — могу только представлять как это может выглядеть, да поверить вам на слово. Но что-то мне подсказывает, что не все так гладко будет, как вы пытаетесь тут представить.
Хотя может оказаться, что я и ошибаюсь.
Re[6]: Некоторые мысли о LINQ
От: VladD2 Российская Империя www.nemerle.org
Дата: 13.01.09 19:46
Оценка:
Здравствуйте, Tissot, Вы писали:

T>Ты не успел. Я уже смирился с попыткой что-либо доказать.

T>С "unit of work" подходом я работал и достаточно много. С ER — могу только представлять как это может выглядеть, да поверить вам на слово. Но что-то мне подсказывает, что не все так гладко будет, как вы пытаетесь тут представить.
T>Хотя может оказаться, что я и ошибаюсь.

А вы его есть пробовали? (с) Реклама майонеза.

В общем, распробуй оба блюда и тогда можно будет говорить предметно.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[14]: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 14.01.09 11:04
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Что касается блокировок, то селекты обеспечивают их не во всех случаях.

Соыершенно верно.
VD>Фактически полной гарантии можно добиться только при использовании верхнего уровня изоляции, что само по себе снижает эффективность.
Не совсем. "Само по себе" ничто ничего не снижает.
Дело в том, что "уровень изоляции" сам по себе — некоторая фикция. Изоляция либо есть, либо её нет.
Просто обеспечение изоляции должно делаться по-разному, в зависимости от того, что делается в транзакции.
Уровни изоляции позволяют программисту подсказать серверу объем необходимых мер. Можно обойтись вместо них прямыми хинтами на каждый стейтмент, но это путь жедаев.
Фишка — в том, что теоретически инфраструктура сама может выбрать нужный уровень изоляции в том случае, если ей дать полный набор действий, которые нужно выполнить в транзакции.

VD> Но есть простые приемы позволяющие добиться блокировки при исползовании SQL DML. Например, меня "в детстве" учили, что получать значение счетчика надо не так (гипотетический LINQ DML):

VD>
VD>var counter = select counter from table where id = 123;
VD>counter++;
VD>update table set table.counter where id = 123;
VD>

Совершенно верно. Другая фишка — как раз в том, что только такой способ предлагает существующий Linq2sql. Сначала мы делаем select, потом у выбранного объекта делаем table.Counter++, а потом вызываем SaveChanges() или как он там, который построит ровно такой апдейт, как ты написал.

Причем если бы мы писали это на SQL, то можно было бы сделать в первой строчке select with(updlock), что сделало бы семантику эквивалентной семантике твоего второго примера. А если бы мы имели умный фреймворк (тм), то он бы сам добавил upddlock в первый стейтмент, увидев, что прочитанное значение используется в транзакции дальше. (А если бы мы в третьей строчке не стали менять тот же кортеж, то обошлось бы holdlock).

VD>а так:

VD>
VD>update table set counter where id = 123;
VD>select counter from table where id = 123;
VD>

VD>При этом запись будет заблокирована первым выражением и второй выражение вернет всегда верное значение. Блокировка же будет снята во время комита.
VD>Более того мы можем проанализировать измененное значение и если что откатить транзакцию.
Всё правильно. Более того, соврменный MS SQL позволяет тебе записать это одним стейтментом. И очень бы хотелось похожей мощи от Linq, вместо приседаний с unit of work.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[5]: Некоторые мысли о LINQ
От: no4  
Дата: 15.01.09 20:05
Оценка:
Здравствуйте, VladD2, Вы писали:

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

VD>Утверждение о том, что объектная модель более гибка нежели ER в обще-о верно. Но гибкость определяется тем, что модель эта была предназначена для представления объектны графов в памяти, не данных в БД.
VD>Так что именно эта гибкость и становится проблемой. По ER-модели же можно легко создать адекватную ОО-медель. Эта модель не будет иметь возможности оперировать всеми ОО-принципами и подходами, но для обработки данных этого и не надо. Зато управлять данными становится просто и можно делать это эффективно.


А нельзя ли как-то это совместить? С одной стороны данные важны. С другой стороны, хотелось бы манипулировать более высокоуровневыми абстракциями чем Entities.

Например, сделать объектно-ориентированный язвк, чтобы он:

* был декларативныой
* поддерживал транзакции

Сделать некий рантайм, чтобы он трактовал СУБД как некий сопроцессор.

То есть как сейчас JIT транслирует IL в машкод, так подобный JIT транслировал часть IL в SQL и объекты базы данных.
Re[6]: Некоторые мысли о LINQ
От: Sinix  
Дата: 16.01.09 04:33
Оценка:
no4>Например, сделать объектно-ориентированный язвк, чтобы он:

no4> * был декларативныой

no4> * поддерживал транзакции

no4>Сделать некий рантайм, чтобы он трактовал СУБД как некий сопроцессор.


no4>То есть как сейчас JIT транслирует IL в машкод, так подобный JIT транслировал часть IL в SQL и объекты базы данных.


Можно но ненужно. Либо имеем тот же SQL, но раздутый от дополнительных фич, важных клиенту, но никак не серверу. Либо имеем некое подмножество, которое подходит для части сценариев, а для остальных — работайте напрямую с БД. Часть фич типа тех же транзакций для чисто императивных операций сделать практически нереально. Не решает это ничего, в общем.
Re[7]: Некоторые мысли о LINQ
От: no4  
Дата: 16.01.09 19:47
Оценка:
S> Либо имеем некое подмножество, которое подходит для части сценариев, а для остальных — работайте напрямую с БД.

Разве с LINQ сейчас не так?
Re: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 26.01.09 02:02
Оценка: 4 (1) +1
Здравствуйте, VladD2, Вы писали:


VD>Учитывая вышесказанное, довольно глупо ожидать от реализаций LINQ качественной реализации абстракций, для поддержки которых они не предназначены. LINQ просто не должен быть предназначен для обработки объектов путем перебора их в циклах и изменения их свойств. Вместо этого он должен манипулировать наборами сущностей с помощью запросов.

VD>Единственное, что меня радует – это то, что Microsoft-таки показала, как интегрировать ER-подход с современными объектно-ориентированными языками с функциональным уклоном, и кто-то из посторонних сможет реализовать, казалось бы, такие напрашивающиеся для LINQ insert, update и delete. Жаль, что, в отличие от Nemerle, такие языки, как C# и VB, не позволяют расширить свой синтаксис чтобы бесшовно ввести эти операторы в язык. Но хотя бы в виде процедур, принимающих условия в виде деревьев выражений, их можно добавить в любой язык. Продаю идею .
А вот подоспел и ответ из Редмонда. Правда, неофициальный.
Как видишь, идеи манипулирования данными с помощью запросов находят широкий отклик среди передовой общественности.
Считаю, что Nemerle мог бы поддержать инициативу камрада Мэтта Уоррена путем добавления нативного linq-подобного синтаксиса, соответствующего IUpdatable<T>.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[2]: Некоторые мысли о LINQ
От: VladD2 Российская Империя www.nemerle.org
Дата: 26.01.09 18:28
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>А вот подоспел и ответ из Редмонда. Правда, неофициальный.


Ссылочка не открывается.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: Некоторые мысли о LINQ
От: Aen Sidhe Россия Просто блог
Дата: 27.01.09 07:51
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Единственное, что меня радует – это то, что Microsoft-таки показала, как интегрировать ER-подход с современными объектно-ориентированными языками с функциональным уклоном, и кто-то из посторонних сможет реализовать, казалось бы, такие напрашивающиеся для LINQ insert, update и delete. Жаль, что, в отличие от Nemerle, такие языки, как C# и VB, не позволяют расширить свой синтаксис чтобы бесшовно ввести эти операторы в язык. Но хотя бы в виде процедур, принимающих условия в виде деревьев выражений, их можно добавить в любой язык. Продаю идею .


Щас меня запишут в подпевалы.

Когда я впервые увидел linq, я задался вопросом — где insert/update/delete. До сих не понимаю, почему этого не было сделано сразу — ибо сколько геморроя можно было бы избежать

ЗЫ: ссылка Sinclair у меня открылась, там описание вот этой библиотеки.
ЗЗЫ: когда Sinclair успевает все эти блоги читать? о_О
С уважением, Анатолий Попов.
ICQ: 995-908
Re[3]: Некоторые мысли о LINQ
От: Sinclair Россия https://github.com/evilguest/
Дата: 28.01.09 10:29
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Ссылочка не открывается.

Пинай своего провайдера — я только что проверил. Всё работает.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[4]: Некоторые мысли о LINQ
От: VladD2 Российская Империя www.nemerle.org
Дата: 28.01.09 14:27
Оценка:
Здравствуйте, Sinclair, Вы писали:

VD>>Ссылочка не открывается.

S>Пинай своего провайдера — я только что проверил. Всё работает.

Может еще прохожих попинать? Сервер отвечал "Server unavailable" или тупа таймаут.
Сейчас открылся с большим скрипом.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: LINQ rulez ! , но это не только SQL
От: Silver_s Ниоткуда  
Дата: 14.03.09 11:41
Оценка: :)))
Мои размышления о LINQ.
Для вычислительных задач LINQ немеренно крутая штука. Никакие функциональные,декларативные языки теперь даром не нужны.
Под LINQ имею ввиду — содержимое Enumerable + лямбда выражения + Generics + автоматическое выведение типов
+yield+... + то что можно самостоятельно написать по подобию Enumerable (используя основную его концепцию).
Только это как-то долго доходило ... когда эти фичи появлялись казались мелочами. И даже от таких Generic казалось единственная польза это то что с ArrayList чуть попроще работать. А когда все эти фичи объединились, оказалось что в C# появилась новая концепция программирования, более высокоуровневая, объединение декларативного программирования и обычного в одном языке.

В проектах где много вычислительных задач со сложными структурами данных, отбрасывается огромное количество ненужной мышиной возни, по созданию каких-то бессмысленых промежуточных классиков, коллекций,функций, переменных, запихиванию и вытаскиванию из них данных туда-сюда...что-то типа такого.
В таких проектах много LINQ не бывает, чем его больше тем меньше объем кода, лучше читабельность, повторная используемость.
Хотя возможно преборы и бывают...

Если к примеру взять такую задачу(алгоритм), довольно распространенную при работе с графами.
Получение "компонент связности" графа. Т.е. грубо говоря, разделение графа на куски между которыми не было связей,
а внутри каждого куска связи есть (от любой вершины можно добраться до любой другой).
Сам по себе алгоритм простой — выбираем вершину и рекурсивно движемся по связанным вершинам помечая их числом (в уже помеченные не заходим чтобы не зациклится на петлях). Когда закончили обход, потом Выбираем другое число и еще не помеченную вершину и также метим рекурсивно. Когда непомеченых не осталось, все вершины помеченые одинаковым числом входят в одну компоненту связности.
Графы в программе представляют(если не считать матричное представление) либо списком ребер(связей) — одно ребро это пара вершин. Либо представляют в виде списка смежностей — для каждой вершины храним список связанных с ней.

Допустим функция получает список ребер (список пар вершин) и должна вернуть вершины сгруппированые по "компонентам связности".
Если смотреть такие алгоритмы в разной литературе по дискретноой математике, то там самая настоящая мышиная возня, на каком то языке паскале-си-подобном. На таких языках (такими средствами) самого алгоритма совсем чуть-чуть, основной объем кода это возня со структурами данных.
Этот алгоритм можно почти целиком сделать на LINQ и объем кода раз в 5 меньше и читабельность выше, и еще Generic вершины будут.(И вроде даже производительность сильно не подсаживает.)
Две небольшие статические функции. Одна публичная, другая рекурсивная:


//Нахождение "компонент связности" графа. Принимает список ребер графа.
// Возвращает список компонент, в компоненте список вершин.
//если ребра(связи) повторяются то тоже будет работать правильно.
public static List<List<TVertex>> FindConnectivityComponents<TVertex>(IEnumerable<Pair<TVertex, TVertex>> Links) 
    where TVertex: class
{
    Links = Links.Concat(    //добавляем обратные связи
        Links.Select(l => new Pair<TVertex, TVertex> { First = l.Second, Second= l.First })   
        ); 
    Dictionary<TVertex, Pair<TVertex, int>> markedVertexDict =   //ключ-вершина, значение-маркированая вершина
        Links.Select(l => l.First).Distinct()
        .Select(vertex => new Pair<TVertex, int> { First = vertex, Second = 0 })    //превращаем в маркированую
        .ToDictionary(markedVertex => markedVertex.First)
        ;
    var adjucentLists =   //ключ-маркированая вершина, значение-список примыкающих маркированых вершин 
        Links.ToLookup(l => markedVertexDict[l.First], l => markedVertexDict[l.Second]);

    int componentNum = 1;
    foreach (var vertex in markedVertexDict.Values)
        MarkConnectedVertexesRecursive(vertex, componentNum++, adjucentLists);
    return
        markedVertexDict.Values
        .GroupBy(v => v.Second, v => v.First) //(ключ-номер компоненты, значение-вершина)
        .Select(grouping => grouping.ToList())
        .ToList();
}
//Маркирует числом markWithNumber вершины начиная с startVertex, рекурсивно все связаные с ней.
private static void MarkConnectedVertexesRecursive<TVertex>(
    Pair<TVertex, int> startVertex,
    int markWithNumber,
    ILookup<Pair<TVertex, int>, Pair<TVertex, int>> graphAsAdjacentLists)
{
    if (startVertex.Second != 0) //уже прошлись по этой вершине
        return;
    startVertex.Second = markWithNumber;
    foreach (Pair<TVertex, int> linked in graphAsAdjacentLists[startVertex])
        MarkConnectedVertexesRecursive(linked, markWithNumber, graphAsAdjacentLists);
}





И еще примерно такая штука

public class Pair<T1, T2>
{
public T1 First;
public T2 Second;
}

Единственная неприятность безобразия наподобие такого ILookup<Pair<TVertex, int>, Pair<TVertex, int>> ,
надо какие-то фичи в языке что-ли сделать типа синонимов, хотя-бы на уровне компиляции а не рантайм,
чтобы код не засорять излишествами.

И еще хочется чтобы конструкторы имели Generic параметры и по ним выводился создаваемый класс.
например вместо new Pair<int,string>(1,"s") чтобы можно было бы написать new Pair(1,"s") и по конструктору
бы настроился созданный класс. Потому что вместо int,string могут стоять гигантские конструкции с Generic,
а класс Pair (или Triple) могут употребляться часто в разных целях. Анонимными типами их не всегда удается заменить.

И непонятно почему нельзя вызвать статическую функцию без указания Generic параметров класса, если эта функция не
использует Generic параметры класса. тогда можно было бы создать этот самый Pair через его статическую функцию,
с автоматическим выводом типов:
static BPair New<T1,T2>(T1 val1,T2 val2)
{
return new BPair<T1,T2>{First=val1,Second=val2};
}

А так приходится выносить такую функцию в отдельный класс New, чтобы создавать Pair и и другие классы так: New.Pair(1,"s");
Re[2]: LINQ rulez ! , но это не только SQL
От: _DAle_ Беларусь  
Дата: 14.03.09 12:36
Оценка:
Здравствуйте, Silver_s, Вы писали:

S_>Допустим функция получает список ребер (список пар вершин) и должна вернуть вершины сгруппированые по "компонентам связности".

S_>Если смотреть такие алгоритмы в разной литературе по дискретноой математике, то там самая настоящая мышиная возня, на каком то языке паскале-си-подобном. На таких языках (такими средствами) самого алгоритма совсем чуть-чуть, основной объем кода это возня со структурами данных.
S_> Этот алгоритм можно почти целиком сделать на LINQ и объем кода раз в 5 меньше и читабельность выше, и еще Generic вершины будут.(И вроде даже производительность сильно не подсаживает.)
S_>Две небольшие статические функции. Одна публичная, другая рекурсивная:

Все это неплохо, безусловно. Я просто приведу код, делающий почти тоже самое на дуболомном с++, чтобы можно было нормально сравнить объем кода и читабельность.

S_>
S_>//Нахождение "компонент связности" графа. Принимает список ребер графа.
S_>// Возвращает список компонент, в компоненте список вершин.
S_>//если ребра(связи) повторяются то тоже будет работать правильно.
S_>public static List<List<TVertex>> FindConnectivityComponents<TVertex>(IEnumerable<Pair<TVertex, TVertex>> Links) 
S_>    where TVertex: class
S_>{
S_>    Links = Links.Concat(    //добавляем обратные связи
S_>        Links.Select(l => new Pair<TVertex, TVertex> { First = l.Second, Second= l.First })   
S_>        ); 
S_>    Dictionary<TVertex, Pair<TVertex, int>> markedVertexDict =   //ключ-вершина, значение-маркированая вершина
S_>        Links.Select(l => l.First).Distinct()
S_>        .Select(vertex => new Pair<TVertex, int> { First = vertex, Second = 0 })    //превращаем в маркированую
S_>        .ToDictionary(markedVertex => markedVertex.First)
S_>        ;
S_>    var adjucentLists =   //ключ-маркированая вершина, значение-список примыкающих маркированых вершин 
S_>        Links.ToLookup(l => markedVertexDict[l.First], l => markedVertexDict[l.Second]);

S_>    int componentNum = 1;
S_>    foreach (var vertex in markedVertexDict.Values)
S_>        MarkConnectedVertexesRecursive(vertex, componentNum++, adjucentLists);
S_>    return
S_>        markedVertexDict.Values
S_>        .GroupBy(v => v.Second, v => v.First) //(ключ-номер компоненты, значение-вершина)
S_>        .Select(grouping => grouping.ToList())
S_>        .ToList();
S_>}
S_>//Маркирует числом markWithNumber вершины начиная с startVertex, рекурсивно все связаные с ней.
S_>private static void MarkConnectedVertexesRecursive<TVertex>(
S_>    Pair<TVertex, int> startVertex,
S_>    int markWithNumber,
S_>    ILookup<Pair<TVertex, int>, Pair<TVertex, int>> graphAsAdjacentLists)
S_>{
S_>    if (startVertex.Second != 0) //уже прошлись по этой вершине
S_>        return;
S_>    startVertex.Second = markWithNumber;
S_>    foreach (Pair<TVertex, int> linked in graphAsAdjacentLists[startVertex])
S_>        MarkConnectedVertexesRecursive(linked, markWithNumber, graphAsAdjacentLists);
S_>}       
S_>


template<class TVertex> 
vector<vector<TVertex> > FindConnectivityComponents(const vector<pair<TVertex, TVertex> >& Links) 
{
    map<TVertex, int> vertexDict;
    vector<vector<int> > adjacentList;
    vector<vector<TVertex> > result;
    vector<TVertex> vertices;
    for (size_t i = 0; i < Links.size(); ++i)
    {
        if (vertexDict.count(Links.first) == 0)
        {
            vertexDict[Links.first] = vertexDict.size();
            vertices.push_back(Links.first);
            adjacentList.push_back(vector<int>());
        }
        if (vertexDict.count(Links.second) == 0)
        {
            vertexDict[Links.second] = vertexDict.size();
            vertices.push_back(Links.second);
            adjacentList.push_back(vector<int>());
        }
        adjacentList[vertexDict[Links.first]].push_back(vertexDict[Links.second]);
        adjacentList[vertexDict[Links.second]].push_back(vertexDict[Links.first]);
    }
    vector<int> was(vertices.size(), 0);
    for (size_t i = 0; i < vertices.size(); ++i)
        if (was[i] == 0)
        {
            result.push_back(vector<TVertex>())
            MarkConnectedVertexesRecursive(i, adjacentList, vertices, result);       
        }
    return result;
}

template<class TVertex>
void MarkConnectedVertexesRecursive(
    int vertex,
    const vector<vector<int> >& adjacentList,
    const vector<TVertex>& vertices,
    const vector<int>& was,
    vector<vector<TVertex> >& result 
{
    was[vertex] = 1;
    result.back().push_back(vertices[vertex[vertex]]);
    for (size_t i = 0; i < adjacentList[vertex].size(); ++i)
        if (was[adjacentList[vertex][i]] == 0) 
           MarkConnectedVertexesRecursive(adjacentList[vertex][i], adjacentList, vertices, was, result);
}

Теперь можно избивать пещерный императивный код на плюсах на примере.
Re[3]: LINQ rulez ! , но это не только SQL
От: Silver_s Ниоткуда  
Дата: 14.03.09 15:27
Оценка:
Здравствуйте, _DAle_, Вы писали:

__DA>... Я просто приведу код, делающий почти тоже самое на дуболомном с++, чтобы можно было нормально сравнить объем кода и читабельность.



Ну, конечно, ATL (или как его там) не такая уж беспомощная вещь...
А читабельность все же (по крайней мере для меня) выше у варианта на LINQ.
На LINQ читабельность будет высокая если семантика, и можно сказать синтаксис (т.к. это почти язык в языке C#),
всех функций в Enumerable до боли знакома.
Читабельность снижают for с индексами, if внутри циклов, крупные тела циклов, большое количество вложенных индексаторов
например такое не очень красиво выглядит:
adjacentList[vertexDict[Links[i].first]].push_back(vertexDict[Links[i].second]);
Кстати в в тексте пропущен индексатор после Links (или промежуточная переменная не создана)
Снижают читабельность и тайные(неявные) связи, например между векторами adjacentList и vertices

В варианте на LINQ код более плоский, последовательный.

Хотя, конечно, никаких проблем с таким кодом на C++ нету, достаточно компактный.
Но он все таки немного по другому сделан, просто есть альтернативные варианты реаизации этой функции.
Но примеры можно найти и когда 3-4 строчки против 15.

Но так издеваться над данными как LINQ, кромсать, переделывать, переорганизовывать,обрабатывать, в 3-4 строчек
кода традиционный ATL все-таки не может.
Все же основная польза от LINQ даже не такие функции, как приведенна выше, а мелкие но меткие вставки в 2-3 строчки
разбросаные по всему проекту.
Re[2]: LINQ rulez ! , но это не только SQL
От: Sinclair Россия https://github.com/evilguest/
Дата: 20.03.09 05:04
Оценка:
Здравствуйте, Silver_s, Вы писали:


S_>И еще хочется чтобы конструкторы имели Generic параметры и по ним выводился создаваемый класс.

S_>например вместо new Pair<int,string>(1,"s") чтобы можно было бы написать new Pair(1,"s") и по конструктору
S_>бы настроился созданный класс. Потому что вместо int,string могут стоять гигантские конструкции с Generic,
S_>а класс Pair (или Triple) могут употребляться часто в разных целях. Анонимными типами их не всегда удается заменить.

Для этого достаточно сделать вот так:
public static Pair<T1, T2> NewPair<T1, T2>(T1 t1, T2 t2)
{
  return new Pair<T1, T2>(t1, t2);
}

Тогда твой код будет немножко покороче:
public static List<List<TVertex>> FindConnectivityComponents<TVertex>(IEnumerable<Pair<TVertex, TVertex>> Links) 
    where TVertex: class
{
    Links = Links.Concat(    //добавляем обратные связи
        Links.Select(l => NewPair(l.Second, l.First))
            ); 
    var markedVertexDict =   //ключ-вершина, значение-маркированая вершина
        Links.Select(l => l.First).Distinct()
        .Select(vertex => NewPair(vertex, 0))    //превращаем в маркированую
        .ToDictionary(markedVertex => markedVertex.First)
        ;
    var adjucentLists =   //ключ-маркированая вершина, значение-список примыкающих маркированых вершин 
        Links.ToLookup(l => markedVertexDict[l.First], l => markedVertexDict[l.Second]);

    int componentNum = 1;
    foreach (var vertex in markedVertexDict.Values)
        MarkConnectedVertexesRecursive(vertex, componentNum++, adjucentLists);
    return
        markedVertexDict.Values
        .GroupBy(v => v.Second, v => v.First) //(ключ-номер компоненты, значение-вершина)
        .Select(grouping => grouping.ToList())
        .ToList();
}
//Маркирует числом markWithNumber вершины начиная с startVertex, рекурсивно все связаные с ней.
private static void MarkConnectedVertexesRecursive<TVertex>(
    Pair<TVertex, int> startVertex,
    int markWithNumber,
    ILookup<Pair<TVertex, int>, Pair<TVertex, int>> graphAsAdjacentLists)
{
    if (startVertex.Second != 0) //уже прошлись по этой вершине
        return;
    startVertex.Second = markWithNumber;
    foreach (Pair<TVertex, int> linked in graphAsAdjacentLists[startVertex])
        MarkConnectedVertexesRecursive(linked, markWithNumber, graphAsAdjacentLists);
}
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re: Некоторые мысли о LINQ
От: Jakobz Россия  
Дата: 23.03.09 22:04
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Чтобы изменить данные в обеих реализациях LINQ нужно получить объект, изменить его свойства, поместить этот объект в специальный контекст (если он еще не находится в нем) и, в конце концов, выполнить у этого контекста процедуру записи. Это тот же самый подход, что используется в Hibernate и ему подобных PI-средах. И нужен этот подход именно потому, и только для того, чтобы скрыть от разработчика реальную – реляционную – суть обрабатываемых данных, и позволить ему возиться с объектами, как будто они являются полноценными (в смысле ООП) объектами, а не отображением ER-сущностей.


Это нужно не для того, чтобы скрыть реляционную модель. Это нужно потому, что кроме запросов там есть еще и контроль т.н. "optimistic concurrency". А это — очень немаловажная часть работы с базой данных в типичных сценариях. Про это часто забывают, а когда в конце-концов сталкиваются — о-го-го как огребают граблями по голове. А тут оно как-то вроде неплохо приделано: вроде и не мешает, и вроде как на виду.
А потом — какой ты хочешь API для insert/update в плане передачи значений строчки? Как-бы самый логичный — это использовать для этого объект, который уже замэплен на таблицу. А оно так и сделано.
Или ты имеешь ввиду всякие вставки с параллельным селектом из других таблиц или "update X set Y = 0 where"? Если да — то это тоже отдельная история на мой взгляд. Это очень нечасто требуется, реализовать сложно, это выпадает из концепции. Да и красота — она в простоте
Re[2]: Некоторые мысли о LINQ
От: VladD2 Российская Империя www.nemerle.org
Дата: 23.03.09 23:02
Оценка:
Здравствуйте, Jakobz, Вы писали:

J>Это нужно не для того, чтобы скрыть реляционную модель. Это нужно потому, что кроме запросов там есть еще и контроль т.н. "optimistic concurrency". А это — очень немаловажная часть работы с базой данных в типичных сценариях. Про это часто забывают, а когда в конце-концов сталкиваются — о-го-го как огребают граблями по голове. А тут оно как-то вроде неплохо приделано: вроде и не мешает, и вроде как на виду.


С блокировками у текущего подхода только больше проблем. А на запросах я тебе любую модель изобразить смогу.

J>А потом — какой ты хочешь API для insert/update в плане передачи значений строчки? Как-бы самый логичный — это использовать для этого объект, который уже замэплен на таблицу. А оно так и сделано.


Этот вопрос требует продумывания. Но ясно одно, что нужно не только иметь возможность изменить один объект, но и иметь возможность изменить одним запросом группу объектов (точнее строк/кортежей данных).

J>Или ты имеешь ввиду всякие вставки с параллельным селектом из других таблиц или "update X set Y = 0 where"?


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

J> Если да — то это тоже отдельная история на мой взгляд. Это очень нечасто требуется, реализовать сложно, это выпадает из концепции. Да и красота — она в простоте


Тебе, может быть. Мне это периодически требовалось.
Что касается концепции, то это какие-то твои личные концепции. Я как-то не вижу выпадения из концепций linq-а. Вот отсутствие возможности изменить объект запросом — это и правда выпадение из концепции.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Некоторые мысли о LINQ
От: Jakobz Россия  
Дата: 24.03.09 00:06
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>С блокировками у текущего подхода только больше проблем. А на запросах я тебе любую модель изобразить смогу.


Проблем много, но все-таки в LINQ to SQL проблемы с concurency хотя бы как-то выпаливаются и выдаются в относительно удобоваримом виде. Можно было бы как-то отделить это, чтобы можно было и самостоятельно эту проблему решать. Но, как показывает практика, если постоянно не напоминать об этой проблеме, то среднестатистические C#-разработчики просто забудут или отложат на потом. И я считаю что вся эта эпопея с обязательным DataContext-ом — очень мудрое решение, хотя это и копромис. Оно решает далеко не все проблемы с конкурентным доступом, но, как показывает практика, часто и такого уже — за глаза.
Ну и вообще, в целом, я только хотел сказать что db.InsertOnUpdate() — оно именно из-за этого так, а не для высоких ORM-целей.

VD>Что касается концепции, то это какие-то твои личные концепции. Я как-то не вижу выпадения из концепций linq-а. Вот отсутствие возможности изменить объект запросом — это и правда выпадение из концепции.


Я концепцию Linq to sql не стал бы идеализировать. Это всего лишь совокупность средств, призваных решать типовые задачи по работе с базой, без каких-либо потугов на панацею. А типовые задачи такие:
1. достать данные из базы. Достать по возможности быстро и без гемора в любых его проявлениях. Достать только необходимый объем: чем меньше — тем лучше, но без фанатизма.
2. засунуть данные назад в базу. Чаще всего их немного: пара-дюжина измененных руками на UI объектов, пара строчек каких-либо свежеполученых откуда-либо данных, и т.п.
3. найти и помочь программисту разрулить проблемы конкурентного изменения данных
Все остальные задачи по работе с БД в типовых проектах составляют часто весьма большую, но не бОльшую часть.
Задачи, кроме этих трех, бывают весьма разнообразные. И непонятно как их обобщить. Одному нужно по ночам заливать в базу гигабайты blob-ов, другой увеличивает оклад через update X set salary = salary + 100 where gender = 'F', и т.п. Есть еще миграция данных при изменении схемы, где массовые update-ы и insert-ы как раз очень кстати.
Но это все хрен впихнешь в общую концепцию.

В общем моё имхо — ни к чему было пытаться это все впихнуть в легкий и прозрачный Linq to sql. И если ты, когда припрет, напишешь sqlCommand.CommandText = "update ... set ... where ...", динозавр не прибежит и не откусит тебе голову*

*http://xkcd.com/292/
Re[4]: Некоторые мысли о LINQ
От: VladD2 Российская Империя www.nemerle.org
Дата: 24.03.09 19:16
Оценка:
Здравствуйте, Jakobz, Вы писали:

J>В общем моё имхо — ни к чему было пытаться это все впихнуть в легкий и прозрачный Linq to sql. И если ты, когда припрет, напишешь sqlCommand.CommandText = "update ... set ... where ...", динозавр не прибежит и не откусит тебе голову*


Это будет резко отличаться от подхода с датаконтекстом и с большой вероятностью приведет к проблемам.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.