tag:blogger.com,1999:blog-19050129359630644522024-02-20T20:26:03.757+03:00Exception blogМы уже победили, просто это еще не так заметно...Laverlinhttp://www.blogger.com/profile/02456687838758248754noreply@blogger.comBlogger4125tag:blogger.com,1999:blog-1905012935963064452.post-71951643586508012362010-10-03T16:42:00.003+04:002010-10-03T18:41:57.855+04:00Небольшой этюд с TPLЧто, по вашему мнению, должен вывести следующий код?<br />
<br />
<pre>try
{
Task.Factory.StartNew(() => Debug.WriteLine("exceptionless task"))
.ContinueWith(t =>
Debug.WriteLine("exception happened... " + t.Exception),
TaskContinuationOptions.OnlyOnFaulted)
.Wait();
}
catch (Exception exception)
{
Debug.WriteLine("твоюж мать... " + exception);
}</pre>
<br />
<a name='more'></a><br />
<cut title="далее"> <br />
Ну, очевидно выведет он ...<br />
<br />
<br />
<em>exceptionless task</em><br />
<em>твоюж мать... System.AggregateException: One or more errors occurred. ---> System.Threading.Tasks.TaskCanceledException: A task was canceled.</em><br />
<br />
иначе бы я не спрашивал =) А вот почему?<br />
<br />
Когда я пытался приспособить это к делу, то руководствовался следующей логикой. У нас есть цепочка тасков, родительский выполнился успешно, дочерний предикату не удовлетворяет и значит не будет выполнен вообще – все отлично, расходимся. Но таким способом, как показала практика, данный код не работает. Если дочерний Task предикату не удовлетворяет, то будет выброшен TaskCancellationException. Более того, это исключение будет выброшено только в том случае, если нам нужен результат выполнения цепочки тасков, то есть если в конце у нас стоит вызов Result или Wait(), а если результат не нужен, то исключение вообще никогда не выбросится, даже при финализации таска, что противоречит общей логике TPL. <br />
<br />
Разработчики же, на прямой вопрос «а почему собственно так», ответили примерно следующим образом. Если нужен результат выполнения таска, то нужно дождаться выполнения всех тасков, а так как дочерний таск не выполнится никогда, то получается логический дедлок, выйти из которого и помогает вышеописанное исключение. <br />
<br />
Строго говоря, логика в их словах есть, но на мой взгляд она все равно какая-то странная. Зачем нам ждать выполнения дочернего таска или ловить исключение, если мы явно указали, что этот таск должен выполняться только при определенных условиях – непонятно. <br />
<br />
Поставленную задачу вполне можно решить, например, следующим способом:<br />
<br />
<pre>try
{
Task.Factory.StartNew(() => Debug.WriteLine("exceptionless task"))
.ContinueWith(t =>
{
if (t.IsFaulted)
{
Debug.WriteLine("exception happened... " + t.Exception);
}
}, TaskContinuationOptions.ExecuteSynchronously)
.Wait();
}
catch (Exception exception)
{
Debug.WriteLine("твоюж мать... " + exception);
}
</pre>
<br />
Но вот для каких практических случаев может пригодится текущее поведение TaskContinuationOptions – для меня пока загадка... </cut>Laverlinhttp://www.blogger.com/profile/02456687838758248754noreply@blogger.com0tag:blogger.com,1999:blog-1905012935963064452.post-56659031950900103842010-04-11T15:03:00.006+04:002010-04-11T18:46:23.706+04:00Переезд...Блоги на GDN окончательно меня задрали, и я решил преодолеть свою лень и найти другую площадку для нерегулярного графоманства на околодевелоперские темы... Видимо это будет <a href="http://laverlin.blogspot.com/">здесь</a>, но окончательно я еще не определился. <br />
<a name='more'></a> <cut title="далее"><br />
В принципе, новый дизайн GDN-а, сооруженный с божъей и битриксовской помощью, мне нравится сильно больше того что было. Но радовался я этому ровно до тех пор, пока не пришлось воспользоваться редакторской частью... Весьма унылая конструкция.<br />
Предыдущий dasBlog, прикрученый Тимой, конечно не блистал красотой дизайна и переодически валился, но в функциональном плане, надо признать, там было сильно богаче и, главное, удобнее. Причем понял я это сейчас, когда попытался воспользоваться чем-то еще, а тогда конечно да - плевался тоже.. =)<br />
<br />
Вообще - удивительный феномен, наблюдать его можно не только с блогами, но блоги тут весьма характерны. Казалось бы, ну что блоги? Весьма примитивная, по сути своей, вещь, форумы и те сильно сложнее. Движков блогов, до попы, только ленивый не пишет. Но вот попытавшись найти движек для своих, не сильно нестандартных целей, понял, что не смотря на все многообразие, того что нужно - нет. Вот тот же гугловский blogger - вроде бы все хорошо, но до чего же убогие стандартные шаблоны! Такое впечатление, что они просто не предназначены для написания текстов объемом больше трех абзацев. Да, они конечно предоставляют возможность, если что отредактировать сообщение в html, но все равно потом стили шаблона убъют все форматирование, вот и вертись как хочешь...<br />
Блоги на MSN - примерно та же фигня, шаблоны вроде по приятнее, но кастомизации еще меньше. <br />
Вообще, давно уже бордит тезис, что в популярности сервиса дизайн - далеко не главное. Из популярных сервисов с приличным дизайном на ум только хабр и stackoverflow пожалуй приходит, ну и rsdn еще ничего... От всего остального просто слезы на глаза наворачиваются - auto.ru, ЖЖ, sql.ru, odnoklassniki, facebook/vkontakte, как этим вообще пользоваться можно? От стандартных phbb-шных форумов просто уже тошнит.... )) Ужас, но все эти сервисы наудивление популярны, не взирая ни на что - парадокс =)<br />
<br />
P. S.<br />
Да, всем фанатам гугла и юзабилити их продуктов, предлагается догадаться как получить rss feed из блога на blogger.com =)<br />
</cut>Laverlinhttp://www.blogger.com/profile/02456687838758248754noreply@blogger.com4tag:blogger.com,1999:blog-1905012935963064452.post-88343312377768256742010-04-05T12:24:00.000+04:002010-04-11T14:11:09.311+04:00Reactive Framework (Rx)Меня всегда восхищают решения с одной стороны простые и элегантные, а с другой - на удивление эффективные и удобные. Примером таких решений может служить LINQ – это удивительная штука. Внеся всего несколько изменений в синтаксис языка – анонимные типы, расширяющие методы, вывод типов (var), инициализаторы и лямбды (причем все это, кроме разве что анонимных типов – чистой воды синтаксический сахар), мы получили удивительно удобную конструкцию для работы с коллекциями, причем даже с уже давно написанными, и сейчас уже сложно представить приложение без элементов LINQ-а, настолько он получился удачным.</P><a name='more'></a><br />
<p>И вот, один из основных авторов линка Эрик Мейер (Erik Mejier) снова радует нас очередным фантастическим решением, на этот раз у него дошли руки до событий и прочей асинхронности. Его подход, как мы убедимся, элегантен, прост, требует минимальных изменений в базовой библиотеке и вместе с тем уже сейчас видно, что он окажется на удивление удачным.</P><p>Суть предложенного им решения лежит на поверхности – представить события в виде последовательностей данных, поступающих из какого-либо источника. Например, по выражению самого Эрика «мышка – это огромная база данных с миллионами записей координат положения мыши и всяких кликов». А раз это коллекция данных, значит можно применить LINQ запросы по этим данным. =) Собственно, альтернативное название этого подхода LINQ 2 Events, но на мой взгляд оно не очень удачное так как сама технология много шире.</P><p>Сам LINQ2Object, работает поверх пары интерфейсов IEnumerable/IEnumerator, которые отлично справляется со своей задачей, но вот здесь-то на пути представления событий в виде набора данных, есть одна досадная помеха – идеологически эти интерфейсы являются интерактивными (interactive). Это означает, что потребитель сам управляет получением новой порции объектов – до тех пор, пока потребитель не вызвал метод MoveNext(), источник данных никак не может впихнуть в потребителя новую порцию информации. В то время как для работы с событиями нужно обратное, чтобы потребитель реагировал на появление новых данных в источнике – следовательно, для решения данной проблемы нужен некий реактивный (Reactive) аналог такого же механизма. То есть, такая конструкция потребителя данных, которая не управляла бы источником, а наоборот – реагировала на его события, или другими словами, сама управлялась им. А так как во всем остальном пара интерфейсов IEnumerable/IEnumerator вполне хороша, то, оцените изящество решения: достаточно эту пару интерфейсов вывернуть наизнанку, чтобы получить требуемый эффект. :) Так и родилась пара других интерфейсов - IObserver/IObservable. </P><p>Если интересно как это происходило в подробностях, то очень рекомендую посмотреть одну из видеозаписей Эрика или его коллег про Rx, это действительно интересно. =) </P><p><a href="http://channel9.msdn.com/shows/Going+Deep/E2E-Erik-Meijer-and-Wes-Dyer-Reactive-Framework-Rx-Under-the-Hood-1-of-2/">http://channel9.msdn.com/shows/Going+Deep/E2E-Erik-Meijer-and-Wes-Dyer-Reactive-Framework-Rx-Under-the-Hood-1-of-2/</A> </P><p><a href="http://channel9.msdn.com/shows/Going+Deep/Expert-to-Expert-Brian-Beckman-and-Erik-Meijer-Inside-the-NET-Reactive-Framework-Rx/">http://channel9.msdn.com/shows/Going+Deep/Expert-to-Expert-Brian-Beckman-and-Erik-Meijer-Inside-the-NET-Reactive-Framework-Rx/</A> </P><p><a href="http://channel9.msdn.com/posts/Charles/Erik-Meijer-Rx-in-15-Minutes/">http://channel9.msdn.com/posts/Charles/Erik-Meijer-Rx-in-15-Minutes/</A></P><p>Здесь же я просто в сжатом виде опишу что куда переехало.</P><p>Так как изменилось только направление вызовов, то действовать можно чисто механически. Интерфейс IEnumerable имеет единственный метод GetEnumerator(), который возвращает IEnumerator. В случае же IObservable, будет тоже один метод Subscribe, который однако, так как связь развернута в другую сторону, возвращать не будет ничего (точнее возвращать будет IDisposable), а вот в качестве параметра будет принимать экземпляр IObserver. Тут все просто и прозрачно... </P><p>Далее, интерфейс IEnumerator оборудован методом MoveNext(), который возвращает false, если добрались до конца списка или выкидывает исключение, если случилась какая непредвиденная фигня. Значит интерфейс IObserver должен быть оборудован методами OnCompleted() и OnError(Exception e), чтобы определить, что делать, если данные в источнике закончились или случилась какая неожиданность. И, наконец, в IEnumerator-е есть свойство T Current, возвращающее текущий элемент, значит IObserver должен быть метод void OnNext(T), посредством которого источник будет поставлять очередной элемент.</P><p>Таким образом, на глазах изумленной публики, вывернув наизнанку интерфейсы IEnumerable/IEnumerator, мы получили IObservable/IObserver, что является ни чем иным, как реализацией паттерна Observer (обозреватель, он же публикатор/подписчик). Да, если кто не в курсе, то IEnumerable/IEnumerator – это паттерн Iterator. Все вышеизложенное подводит нас к мысли о том, что паттерны Iterator и Observer – близнецы-братья, один является зеркальным отражением другого, этаким альтер эго. Причем вся красота этого решения в том, что один паттерн из другого получается чисто механически, вызовы просто разворачиваются в другую сторону и никаких специальных случаев обрабатывать не надо! Эрик еще ехидничал, что не понимает, как эти ребята из GoF, описавшие еще пятнадцать лет назад оба этих паттерна, могли не заметить такого вопиющего дуализма. =))</P><p>Ну чтож, это все действительно красиво и элегантно, очевидно, что навернуть поверх этих двух интерфейсов набор линковских методов расширений – дело техники. Но какая с этого польза?</P><p>Однако практический эффект от этого решения сложно переоценить. Глобально, не считая множества приятных мелочей, есть два положительных момента.</P><ol><li>Мы получили способ комбинирования событий. В реальных приложениях довольно частно нужно иметь обработчик на комбинацию событий, причем не просто на комбинацию, а на комбинацию со сложными условиями, например, когда одно событие возникает только после другого и если этому не предшествовало третье. С помощю Rx, такая задача решается одним запросом.</LI>
<li>Но самое крутое, что мы получили единый (!) механизм работы не только с событиями, но и со всеми асинхронными операциями. То есть, все события, асинхронные паттерны, TPL и любая другая параллельно-асинхронная конструкция – отлично покрываются этой моделью и все это тоже можно комбинировать между собой линковскими запросами посредством Rx.</LI> </OL><p>Причем, всего этого удалось добиться лишь внеся интерфейсы IObservable/IObserver в базовую библиотеку (.Net 4 уже будет поставляться с этими интерфейсами), ну и, естественно, предоставив рядышком еще одну библиотеку (собственно Reactive Framework) с реализацией LINQ-а и некоторыми другими хелперными методами, о которых мы поговорим ниже. Как видно, здесь даже не пришлось трогать язык, просто нет необходимости... :) Более того, когда только Эрик впервые обнародовал саму идею, тут же нашлись энтузиасты, которые реализовали свою версию этих интерфейсов и необходимых методов в своих проектах, и убедились, что все отлично работает.</P><p>Что же входит непосредственно в Reactive Framework? Кроме LINQ-овских расширений для построения запросов, там присутствует большое количество хелперных методов, помогающих построить реализацию описанных выше интерфейсов. Причем не только с нуля, но и на основе уже имеющихся событий, асинхронных вызовов BeginXxx/EndXxx (APM-паттерн), временных интервалов, обычных коллекций, генераторов и байт знает чего еще... Таким образом, как только выйдет Rx, его можно будет сразу же использовать для работы с уже имеющимся сейчас кодом. </P><p>Кроме того, в Rx входит несколько дополнительных методов для работы с коллекциями и событиями (они разнесены по разным сборкам Interactive и Reactive, соответственно), которых нет в обычном LINQ-е, но к которым давно привыкли в функциональных языках.</P><p>Самое время для примера? </P><p>Допустим, у нас есть задача - обратиться по нескольким веб-адресам (несколько раз, для надежности и естественно асинхронно, чтобы не терять время попусту) и определить, отвечают ли они. И если ни разу добиться ответа не удалось – вывести этот провинившийся url.</P><p>Тогда решение может быть таким - пусть у нас есть коллекция подозрительных url-ов.</P><div id="IDARKCYC"><table class="code" width="98%"><tr><td><br />
<pre><span class="KEYWORD">string</SPAN>[] urls = { <span class="STRING">"http://dfsdfsdf.rt"</SPAN>, <span class="STRING">"http://rsdn.ru"</SPAN>, <span class="STRING">"http://google.com"</SPAN>, <span class="STRING">"http://rsdn.ru/qweqwe"</SPAN>, <span class="STRING">"http://rbc.ru"</SPAN> };
</PRE></TD></TR>
</TABLE></DIV><p>Для каждого url-а нам нужно создать объект выполняющий запрос</P><div id="IDABLCYC"><table class="code" width="98%"><tr><td><br />
<pre>urls.Select(url => <span class="KEYWORD">new</SPAN> { Url = url, WebRequest = WebRequest.Create(url) })
</PRE></TD></TR>
</TABLE></DIV><p>И подписаться на события получения такого объекта, предварительно сконвертировав это дело в Observable коллекцию</P><div id="IDAHLCYC"><table class="code" width="98%"><tr><td><br />
<pre>.ToObservable().Subscribe(
</PRE></TD></TR>
</TABLE></DIV><p>В подписчике же начинается самое интересное... Нам нужно три раза с интервалом в 5 секунд, асинхронно обратиться по переданному адресу. Здесь на помощь приходит метод Zip, который комбинирует две коллекции таким образом, что их элементы чередуются. Начнем с коллекции временных интервалов, здесь события случаются строго через 5 секунд.</P><div id="IDALLCYC"><table class="code" width="98%"><tr><td><br />
<pre>Observable.Interval(TimeSpan.FromSeconds(5)).Zip(
</PRE></TD></TR>
</TABLE></DIV><p>Теперь к этой цепочке событий надо призиповать асинхронные обращения по адресу.</P><div id="IDAPLCYC"><table class="code" width="98%"><tr><td><br />
<pre>Observable.FromAsyncPattern<WebResponse>(
requestInfo.WebRequest.BeginGetResponse, requestInfo.WebRequest.EndGetResponse)()
</PRE></TD></TR>
</TABLE></DIV><p>Таким не хитрым способом, мы получили из классического APM-паттерна, Observable коллекцию. Только из этой коллекции может прилететь исключение, а надо бы все обработать единым образом, и здесь придет на помощь функция Materialize, которая обернет результат вызова в специальный объект, а повторить вызов трижды, что нужно по условиям задачи, поможет метод Repeat.</P><div id="IDATLCYC"><table class="code" width="98%"><tr><td><br />
<pre>.Materialize().Repeat(3),
</PRE></TD></TR>
</TABLE></DIV><p>Результатом объединения будет только вторая коллекция, так как временной интервал нас не интересует. При этом все три вызова надо объеденить в один буферный объект, чтобы потом проанализировать.</P><div id="IDAXLCYC"><table class="code" width="98%"><tr><td><br />
<pre>(l, r) => r).BufferWithCount(3)
</PRE></TD></TR>
</TABLE></DIV><p>Теперь осталось только найти такие последовательности запросов, которые все завершились неудачей...</P><div id="IDA1LCYC"><table class="code" width="98%"><tr><td><br />
<pre>.Where(
notifications =>
notifications.All(notification => notification.Kind == <span class="STRING">NotificationKind</SPAN>.OnError))
</PRE></TD></TR>
</TABLE></DIV><p>И вывести результат на консоль.</P><div id="IDABMCYC"><table class="code" width="98%"><tr><td><br />
<pre>.Subscribe(n => Console.WriteLine(requestInfo.Url)));
</PRE></TD></TR>
</TABLE></DIV><p></P><p>Полный запрос решающий поставленную задачу может выглядеть так:</P><p></P><div id="IDAJMCYC"><table class="code" width="98%"><tr><td><br />
<pre><span class="KEYWORD">string</SPAN>[] urls = { <span class="STRING">"http://dfsdfsdf.rt"</SPAN>, <span class="STRING">"http://rsdn.ru"</SPAN>, <span class="STRING">"http://google.com"</SPAN>, <span class="STRING">"http://rsdn.ru/qweqwe"</SPAN>, <span class="STRING">"http://rbc.ru"</SPAN> };
urls.Select(url => <span class="KEYWORD">new</SPAN> {Url = url, WebRequest = WebRequest.Create(url)})
.ToObservable().Subscribe(
requestInfo =>
Observable.Interval(TimeSpan.FromSeconds(5)).Zip(
Observable.FromAsyncPattern<WebResponse>(
requestInfo.WebRequest.BeginGetResponse,
requestInfo.WebRequest.EndGetResponse)().Materialize().Repeat(3),
(l, r) => r).BufferWithCount(3)
.Where(notifications =>
notifications.All(notification => notification.Kind == NotificationKind.OnError))
.Subscribe(n => Console.WriteLine(requestInfo.Url)));
</PRE></TD></TR>
</TABLE></DIV><p></P><p></P><p>В заключение хотелось бы заметить, что с появлением Rx мы получили возможность избавиться от мешанины разбросанных по коду обработчиков событий, подписки на них и головной боли по их освобождению, вместо этого асинхронный код теперь можно писать практически «линейно», почти так же как обычный синхронный.</P>Laverlinhttp://www.blogger.com/profile/02456687838758248754noreply@blogger.com0tag:blogger.com,1999:blog-1905012935963064452.post-3120598478341068382008-09-10T00:07:00.001+04:002010-04-11T12:33:21.739+04:00Свершилось чудо или EF vs Linq2SQLТут на днях чудо свершилось, вышел ADO.Net Entity Framework. =) Я, признаться уже и не надеялся, что продукт до релиза доживет и следил за тем что там происходит без особого интереса. Но приятно было услышать, что MS таки преодолела проклятье "ObjectSpaces". :)<br />
<a name='more'></a><br />
Напомню, в кратце, в чем там было дело. Давным давно, еще до выхода FW 1.1 на конференции PDC 2003, традиционно проходящей в Лос-Анжелесе, MS официально объявил о начале работ над технологией взаимодействия с данными под официальным названием "ObjecSpaces". Суть в том, что команда OS нашла фатальный недостаток в существующих ORM (их придумали не они), и решила этот недостаток устранить. Ну, поскольку дело хорошее, то с песнями и плясками приступили, и на вышеупомянутом PDC был предложен даже некий прототип... Но что-то пошло не так, что именно сейчас уже дело темное, и спустя какое-то время проект был заморожен. Тем временем, активно шли работы над другим забавным проектом, под названием WinFS - грубо говоря, это должна была быть объектная файловая система, причем данные должны были лежать в SQLServer-е. Очевидно при таком сценарии без ORM никуда вот и команда ObjectSpaces быстро нашла фатальный недостаток в их системе мапинга (ее придумали не они) и дружно влилась в стройные ряды WinFS team (причем предполагалось, что ObjecSpaces будет поставляться вместе с WinFS в качестве библиотеки). Но, что-то пошло не так, сейчас уже дело темное, и проект WinFS оказался заморожен. Тем временем, в светлые головы Коробкина, Хайлсберга и других талантливых ребят из MS пришла идея LINQ Project, и они начали ее продвигать и разрабатывать. Ясен байт, что подсистема LINQ-а, отвечающая за работу с RDBMS практически ORM (тогда она называлась DLINQ) и команда OS не смогла устоять перед искушением, нашла, по привычной схеме, фатальный недостаток и занялась рализацией DLINQ. В этот момент я, признаюсь, стал тревожится за успех этого во всех отношениях достойного мероприятия, но тут DLINQ трансформировался в Linq2SQL, и от него отделился Entity Frmework, куда и ушла команда OS в полном составе. С этого момента за Linq2SQL можно было быть спокойным, он зарелизился почти в срок... Релиз же EF был отложен, что уже не вызвало удивления. :) И тут, наконец-то случилось чудо, и MS преодолев злой рок разродился релизом ADO .Net Entity Framework. =)))Релиз, безусловно, еще сыроват, не достигнута основная цель всего мероприятия, о чем немного позже, но, тем не менее, это полноценный релиз.. :)<br />
И так, что же такое Entity Framework и для чего он вообще нужен? Зачем MS поддерживать два, практически дублирующих друг-друга решения, EF и Linq2SQL?<br />
<br />
На самом деле, это довольно разумно и у каждого решения есть своя, довольно четко просматривающаяся ниша. Универсальные, всемогучие подходы, вообще вызывают подозрение, тем более в такой скользкой и мутной области, как ORM. Более того, классические универсальные ORM обладают общим фатальным недостатком, именно в силу своей универсальности - вместо решения прикладной задачи, с ростом проекта начинаешь бороться с ORM....<br />
Формально <strong>Linq2SQL</strong> - ORM, он действительно занимается тем, что мапит данные на объекты и обратно, и официально он тоже считается "типа ORM", но это не совсем ORM в общепринятом понимани. Это очень легковесное решение по мапингу данных на SQL и обратно и выполнению запросов прямо к данным, и в этом его прелесть. Он не перегружен ни чем лишним, практически ничего не требует от бизнес-объектов с которыми работает и отлично справляется со своими задачами. Не смотря на свою легковесность и отсутствие функционала, присущего большим классическим ORM, Linq2SQL покрывает практически все потребности при разработке типичного слоя данных. Дело в том, что подавляющее большинство приложений, кторые вообще имеют дело с данными, являются так называемыми "Data Driven" решениями, то есть, их модель предметной области практически полностью совпадает с моделью данных. Таким приложениям не нужны дополнительные прослойки, хитрые абстрагирования бизнес-логики от данных и прочий мутный функционал, и именно для таких приложений Linq2SQL - находка, аналогов почти нет. Причем уникальность и удачность решения заключается в том, что в данном случае ребята честно признались "Да, Data != Object" и работают с данными, как с данными, а не пытаются построить из них "полноценные объекты", как это делает большинство ORM. И, как я уже замечал выше, класс приложений для которых данный подход является наиболее удачным - весьма широк.<br />
<strong>Entity Framework</strong> же, в свою очередь, задумывался как полноценный взрослый ORM для больших мальчиков, которые любят большие игрушки. Ключевое отличие, как уже наверное известно всем, заключается в том, что при использовании EF разработчик имеет дело не напрямую с данными, а с некоей концептуальной моделью приложения. Эта концептуальная модель призвана оградить хрупкую психику разработчика от ужасов работы с данными и служить этаким фронтендом, абстрагирующим суровую действительность. Результатом этой абстракции можно пользоваться как в прикладном коде, так и выставить наружу через веб-сервис или сереализовать в причудливый XML для загадочных целей, ...Причем по задумке, которую, насколько мне известно, пока еще не реализовали, эта концептуальная модель должна быть первичной. То есть, сначала строится модель, а потом, на ее основе, должны автоматически генериться и модель данных и код. Таким образом, вышеупомянутый абстрактный концепт играет роль некоего DSL (языка предметной области), в терминах которого описываются сущности и их взаимодействие между собой, после чего сторится уже конкретная реализация в данных и коде. На данный момент реализован только подход, который задумывался исключительно для поддержки legacy решений - когда первичной является модель данных, а уже на ее основе строится модель концептуальная, собственно этим, как я подозреваю, и объясняется путаница и частичное пересечение с Linq2SQL... Но, видимо ребятам уже совсем свербило выпуститься - и их можно понять... :) Будем надеяться, что все еще будет реализовано. Подобный подход, с явно выделеной концептуальной моделью, так же является достаточно востребованым. Как правило, нужда в нем возникает в Enterprise проектах, с большим количеством бизнес-логики слабо завязанной на данные или когда логика и/или схема данных может меняться в ходе эксплуатации системы, например, при разработке не конечного приложения под конкретного заказчика, а платформы для семейства решений. Приложений такого рода, безусловно меньше, но зато они обычно довольно масштабны. Это не значит, что все Enterprise решения - отданы на откуп EF, там вполне может оказаться очень к месту и Linq2SQL, но применение EF все-таки, в первую очередь, следует искать именно в больших проектах. Для подавляющего большинства рядовых решений, начиная от финансовых систем для родной бухгалтерии и заканчивая веб-приложениями, все концептуальные приседания вокруг абстракций скорее всего окажутся просто не нужны, и даже наоборот, лишь затруднят поддержку.<br />
<br />
Вообще весь проект Entity Framework-а постоянно окружали какие-то слухи и непонятная движуха. Еще до выхода, ряд несознательных товарищей опубликовали "Вотум недоверия" (Entity Framework Vote of Confidence), весьма истеричный документ, упрекающий MS в том, что этот продукт сделали не так как хотелось авторам этого опуса. Даже если закрыть глаза на то, что с чисто технической точки зрения, большинство претензий довольно нелепы, а остальное просто недоделки, сама форма возмущения выглядит совсем не профессионально. Особенно забавляют отсылки к тому что "мы круты, мы тоже писали ORM, мы лучше знаем...". ;)Хуже другое. Очень надеюсь, что мои опасения не оправдаются, но вся эта суета вокруг EF наводит на неприятные мысли. Складывается впечатление, что внутри MS есть две группировки, каждая из которых тянет одеяло на себя, к счастию, силы разума вроде бы побеждают, судя по продуктам, но их оппоненты в отчаянии пытаются использовать совсем уж грязные приемы, а именно задействовать коммюнити и заставить их кричать, что все делается не так. Иными словами, есть нехорошее ощущение, что ребята с этим вотумом выступили не сами, а им кто-то посоветовал, а так как MS к коммюнити старается прислушивается, то это очень серьезный аргумент во внутренней политике. Кроме того, плохо еще и то, что подобный шаг подрывает доверие к коммюнити, есть гораздо более цивилизованные способы донести свою мысль до тех, кто принимает решения в MS.Очень надеюсь, что я ошибаюсь и ребят из NHibrnate-а просто немного занесло.. )Laverlinhttp://www.blogger.com/profile/02456687838758248754noreply@blogger.com0