Show Blogger Panel Hide Blogger Panel
Alex Yakunin

February 27, 2010

News & links to new topics in forum

News are very short:
  • Historically I'm the guy responsible for creating installers, writing revision history notes and finally publishing each new update. So now I'm busy with Help Server as well. Its v3.0 version will be uploaded to our servers tomorrow after final testing of installers.
  • The same event for DataObjects.Net v4.2 must happen on Sunday.
A part of my recent writing activity was devoted to our support forum - we've got a set of questions, and I'd like to highlight some of them:
And finally, Denis Krjuchkov, one more developer from our team, has started to maintain his own blog. Denis is the guy developing most of RDBMS-specific things in DO4 (low-level SQL DOM providers and high-level SQL storage provider used by DO4 - Xtensive.Storage.Providers.Sql). So such features as uber-batching appeared mainly as result of his work. He's an expert in SQL dialects and various implementation details related to each particular RDBMS.

February 23, 2010

Alternative DataObjects.Net download location

Possibly you don't know, but you can download DataObjects.Net builds from Downloads section at Google Code. The files there are normally updated a bit later (the delay varies from several minutes to few days), but we're trying to maintain this location as well.

Versions and locking tests (code samples for Manual): the links

See:
VersionsTest output:
Entity: Person('Alex Yakunin')
          Key: Person, (1)
  VersionInfo: (Alex, Yakunin, null)


Entity: Person('Dmitri Maximov')
          Key: Person, (2)
  VersionInfo: (Dmitri, Maximov, null)


Entity: Company('X-tensive.com', Employees: )
          Key: Company, (3)
  VersionInfo: (0)


Changing X-tensive.com name to Xtensive
Entity: Company('Xtensive', Employees: )
          Key: Company, (3)
  VersionInfo: (1)


Xtensive.Employees.Add(Alex)
Entity: Company('Xtensive', Employees: Person('Alex Yakunin'))
          Key: Company, (3)
  VersionInfo: (2)


Dmitri.Company = Xtensive
Entity: Company('Xtensive', Employees: Person('Dmitri Maximov'), Person('Alex Yakunin'))
          Key: Company, (3)
  VersionInfo: (3)


Transaction rollback test, before:
Entity: Company('Xtensive', Employees: Person('Dmitri Maximov'), Person('Alex Yakunin'))
          Key: Company, (3)
  VersionInfo: (3)


Transaction rollback test, inside:
Entity: Company('Xtensive', Employees: )
          Key: Company, (3)
  VersionInfo: (4)


Transaction rollback test, after:
Entity: Company('Xtensive', Employees: Person('Dmitri Maximov'), Person('Alex Yakunin'))
          Key: Company, (3)
  VersionInfo: (3)

LockingTest output:
This one is really large, but it shows what's happening pretty well.
LockingTest, LockingMode=None, IsolationLevel = ReadCommitted
Counter isn't isolated.
  Thread 1: beginning of transaction
       Thread 2: beginning of transaction
  Thread 1:   reading shared counter
       Thread 2:   reading shared counter
       Thread 2:   delay (333ms)
  Thread 1:   delay (500ms)
       Thread 2:   incrementing counter
       Thread 2:   counter.Value = 1
       Thread 2:   committing transaction
       Thread 2: transaction is committed
       Thread 2: beginning of transaction
       Thread 2:   reading shared counter
       Thread 2:   delay (333ms)
  Thread 1:   incrementing counter
  Thread 1:   counter.Value = 1
  Thread 1:   committing transaction
  Thread 1: transaction is committed
  Thread 1: beginning of transaction
  Thread 1:   reading shared counter
  Thread 1:   delay (500ms)
       Thread 2:   incrementing counter
       Thread 2:   counter.Value = 2
       Thread 2:   committing transaction
       Thread 2: transaction is committed
       Thread 2: beginning of transaction
       Thread 2:   reading shared counter
       Thread 2:   delay (333ms)
  Thread 1:   incrementing counter
  Thread 1:   counter.Value = 2
  Thread 1:   committing transaction
  Thread 1: transaction is committed
  Thread 1: beginning of transaction
  Thread 1:   reading shared counter
  Thread 1:   delay (500ms)
       Thread 2:   incrementing counter
       Thread 2:   counter.Value = 3
       Thread 2:   committing transaction
       Thread 2: transaction is committed
       Thread 2: beginning of transaction
       Thread 2:   reading shared counter
       Thread 2:   delay (333ms)
       Thread 2:   incrementing counter
       Thread 2:   counter.Value = 4
       Thread 2:   committing transaction
       Thread 2: transaction is committed
       Thread 2: beginning of transaction
       Thread 2:   reading shared counter
       Thread 2:   delay (333ms)
  Thread 1:   incrementing counter
  Thread 1:   counter.Value = 3
  Thread 1:   committing transaction
  Thread 1: transaction is committed
  Thread 1: beginning of transaction
  Thread 1:   reading shared counter
  Thread 1:   delay (500ms)
       Thread 2:   incrementing counter
       Thread 2:   counter.Value = 5
       Thread 2:   committing transaction
       Thread 2: transaction is committed
       Thread 2: beginning of transaction
       Thread 2:   reading shared counter
       Thread 2:   delay (333ms)
  Thread 1:   incrementing counter
  Thread 1:   counter.Value = 4
  Thread 1:   committing transaction
       Thread 2:   incrementing counter
       Thread 2:   counter.Value = 6
       Thread 2:   committing transaction
  Thread 1: transaction is committed
  Thread 1: beginning of transaction
  Thread 1:   reading shared counter
  Thread 1:   delay (500ms)
       Thread 2: transaction is committed
       Thread 2: beginning of transaction
       Thread 2:   reading shared counter
       Thread 2:   delay (333ms)
       Thread 2:   incrementing counter
       Thread 2:   counter.Value = 7
       Thread 2:   committing transaction
       Thread 2: transaction is committed
       Thread 2: beginning of transaction
       Thread 2:   reading shared counter
       Thread 2:   delay (333ms)
  Thread 1:   incrementing counter
  Thread 1:   counter.Value = 7
  Thread 1:   committing transaction
  Thread 1: transaction is committed
  Thread 1: beginning of transaction
  Thread 1:   reading shared counter
  Thread 1:   delay (500ms)
       Thread 2:   incrementing counter
       Thread 2:   counter.Value = 8
       Thread 2:   committing transaction
       Thread 2: transaction is committed
       Thread 2: beginning of transaction
       Thread 2:   reading shared counter
       Thread 2:   delay (333ms)
  Thread 1:   incrementing counter
  Thread 1:   counter.Value = 8
  Thread 1:   committing transaction
  Thread 1: transaction is committed
  Thread 1: beginning of transaction
  Thread 1:   reading shared counter
  Thread 1:   delay (500ms)
       Thread 2:   incrementing counter
       Thread 2:   counter.Value = 9
       Thread 2:   committing transaction
       Thread 2: transaction is committed
       Thread 2: beginning of transaction
       Thread 2:   reading shared counter
       Thread 2:   delay (333ms)
       Thread 2:   incrementing counter
       Thread 2:   counter.Value = 10
       Thread 2:   committing transaction
       Thread 2: transaction is committed
       Thread 2: beginning of transaction
       Thread 2:   reading shared counter
       Thread 2:   delay (333ms)
  Thread 1:   incrementing counter
  Thread 1:   counter.Value = 9
  Thread 1:   committing transaction
  Thread 1: transaction is committed
  Thread 1: beginning of transaction
  Thread 1:   reading shared counter
  Thread 1:   delay (500ms)
       Thread 2:   incrementing counter
       Thread 2:   counter.Value = 11
       Thread 2:   committing transaction
       Thread 2: transaction is committed
       Thread 2: beginning of transaction
       Thread 2:   reading shared counter
       Thread 2:   delay (333ms)
  Thread 1:   incrementing counter
  Thread 1:   counter.Value = 10
  Thread 1:   committing transaction
  Thread 1: transaction is committed
  Thread 1: beginning of transaction
  Thread 1:   reading shared counter
  Thread 1:   delay (500ms)
       Thread 2:   incrementing counter
       Thread 2:   counter.Value = 12
       Thread 2:   committing transaction
       Thread 2: transaction is committed
       Thread 2: beginning of transaction
       Thread 2:   reading shared counter
       Thread 2:   delay (333ms)
       Thread 2:   incrementing counter
       Thread 2:   counter.Value = 13
       Thread 2:   committing transaction
       Thread 2: transaction is committed
       Thread 2: beginning of transaction
       Thread 2:   reading shared counter
       Thread 2:   delay (333ms)
  Thread 1:   incrementing counter
  Thread 1:   counter.Value = 11
  Thread 1:   committing transaction
  Thread 1: transaction is committed
  Thread 1: beginning of transaction
  Thread 1:   reading shared counter
  Thread 1:   delay (500ms)
       Thread 2:   incrementing counter
       Thread 2:   counter.Value = 14
       Thread 2:   committing transaction
       Thread 2: transaction is committed
  Thread 1:   incrementing counter
  Thread 1:   counter.Value = 12
  Thread 1:   committing transaction
  Thread 1: transaction is committed
Final counter.Value = 12


LockingTest, LockingMode=None, IsolationLevel = RepeatableRead
There are deadlocks or version conflicts, but counter is isolated.
  Thread 1: beginning of transaction
       Thread 2: beginning of transaction
       Thread 2:   reading shared counter
       Thread 2:   delay (333ms)
  Thread 1:   reading shared counter
  Thread 1:   delay (500ms)
       Thread 2:   incrementing counter
       Thread 2:   counter.Value = 1
       Thread 2:   committing transaction
  Thread 1:   incrementing counter
  Thread 1:   counter.Value = 1
  Thread 1:   committing transaction
  Thread 1: transaction is committed
  Thread 1: beginning of transaction
  Thread 1:   reading shared counter
  Thread 1:   delay (500ms)
       Thread 2:   error: DeadlockException
       Thread 2: transaction is rolled back
       Thread 2: beginning of transaction
       Thread 2:   reading shared counter
       Thread 2:   delay (333ms)
       Thread 2:   incrementing counter
       Thread 2:   counter.Value = 2
       Thread 2:   committing transaction
  Thread 1:   incrementing counter
  Thread 1:   counter.Value = 2
  Thread 1:   committing transaction
       Thread 2:   error: DeadlockException
       Thread 2: transaction is rolled back
  Thread 1: transaction is committed
Final counter.Value = 2


LockingTest, LockingMode=EntityLock, IsolationLevel = RepeatableRead
Still can be a deadlock, since lock happen after read.
  Thread 1: beginning of transaction
       Thread 2: beginning of transaction
  Thread 1:   reading shared counter
  Thread 1:   locking counter
       Thread 2:   reading shared counter
       Thread 2:   locking counter
       Thread 2:   counter is locked
       Thread 2:   delay (333ms)
  Thread 1:   error: DeadlockException
  Thread 1: transaction is rolled back
  Thread 1: beginning of transaction
  Thread 1:   reading shared counter
       Thread 2:   incrementing counter
       Thread 2:   counter.Value = 1
       Thread 2:   committing transaction
       Thread 2: transaction is committed
  Thread 1:   locking counter
  Thread 1:   counter is locked
  Thread 1:   delay (500ms)
       Thread 2: beginning of transaction
       Thread 2:   reading shared counter
  Thread 1:   incrementing counter
  Thread 1:   counter.Value = 2
  Thread 1:   committing transaction
  Thread 1: transaction is committed
  Thread 1: beginning of transaction
  Thread 1:   reading shared counter
       Thread 2:   locking counter
  Thread 1:   locking counter
  Thread 1:   counter is locked
  Thread 1:   delay (500ms)
       Thread 2:   error: DeadlockException
       Thread 2: transaction is rolled back
  Thread 1:   incrementing counter
  Thread 1:   counter.Value = 3
  Thread 1:   committing transaction
  Thread 1: transaction is committed
Final counter.Value = 3


LockingTest, LockingMode=QueryLock, IsolationLevel = RepeatableRead
No deadlocks, counter isolation.
  Thread 1: beginning of transaction
       Thread 2: beginning of transaction
  Thread 1:   reading & locking shared counter
       Thread 2:   reading & locking shared counter
  Thread 1:   delay (500ms)
  Thread 1:   incrementing counter
  Thread 1:   counter.Value = 1
  Thread 1:   committing transaction
  Thread 1: transaction is committed
  Thread 1: beginning of transaction
  Thread 1:   reading & locking shared counter
       Thread 2:   delay (333ms)
       Thread 2:   incrementing counter
       Thread 2:   counter.Value = 2
       Thread 2:   committing transaction
       Thread 2: transaction is committed
       Thread 2: beginning of transaction
       Thread 2:   reading & locking shared counter
  Thread 1:   delay (500ms)
  Thread 1:   incrementing counter
  Thread 1:   counter.Value = 3
  Thread 1:   committing transaction
  Thread 1: transaction is committed
  Thread 1: beginning of transaction
  Thread 1:   reading & locking shared counter
       Thread 2:   delay (333ms)
       Thread 2:   incrementing counter
       Thread 2:   counter.Value = 4
       Thread 2:   committing transaction
       Thread 2: transaction is committed
       Thread 2: beginning of transaction
       Thread 2:   reading & locking shared counter
  Thread 1:   delay (500ms)
  Thread 1:   incrementing counter
  Thread 1:   counter.Value = 5
  Thread 1:   committing transaction
  Thread 1: transaction is committed
  Thread 1: beginning of transaction
  Thread 1:   reading & locking shared counter
       Thread 2:   delay (333ms)
       Thread 2:   incrementing counter
       Thread 2:   counter.Value = 6
       Thread 2:   committing transaction
       Thread 2: transaction is committed
       Thread 2: beginning of transaction
  Thread 1:   delay (500ms)
       Thread 2:   reading & locking shared counter
  Thread 1:   incrementing counter
  Thread 1:   counter.Value = 7
  Thread 1:   committing transaction
  Thread 1: transaction is committed
  Thread 1: beginning of transaction
  Thread 1:   reading & locking shared counter
       Thread 2:   delay (333ms)
       Thread 2:   incrementing counter
       Thread 2:   counter.Value = 8
       Thread 2:   committing transaction
       Thread 2: transaction is committed
       Thread 2: beginning of transaction
       Thread 2:   reading & locking shared counter
  Thread 1:   delay (500ms)
  Thread 1:   incrementing counter
  Thread 1:   counter.Value = 9
  Thread 1:   committing transaction
  Thread 1: transaction is committed
  Thread 1: beginning of transaction
  Thread 1:   reading & locking shared counter
       Thread 2:   delay (333ms)
       Thread 2:   incrementing counter
       Thread 2:   counter.Value = 10
       Thread 2:   committing transaction
       Thread 2: transaction is committed
  Thread 1:   delay (500ms)
       Thread 2: beginning of transaction
       Thread 2:   reading & locking shared counter
  Thread 1:   incrementing counter
  Thread 1:   counter.Value = 11
  Thread 1:   committing transaction
  Thread 1: transaction is committed
  Thread 1: beginning of transaction
  Thread 1:   reading & locking shared counter
       Thread 2:   delay (333ms)
       Thread 2:   incrementing counter
       Thread 2:   counter.Value = 12
       Thread 2:   committing transaction
       Thread 2: transaction is committed
  Thread 1:   delay (500ms)
  Thread 1:   incrementing counter
  Thread 1:   counter.Value = 13
  Thread 1:   committing transaction
  Thread 1: transaction is committed
Final counter.Value = 13

DataObjects.Net v4.2 RC2 is available

It's obvious we need a bit more time to release v4.2 - partially, because Manual still isn't finished (that's because of the next part), and partially, because there were few more things to fix and refactor.

But there are good news:
  • I was able to review VersionInfo API and DisconnectedState on this week, and, although there was certain amount of refactoring, these parts are now ready to be shown.
  • Since we don't publish v4.2 release, I decided have updated v4.2 Release Candidate to the latest version (RC2). All the bugs we've eliminated on the previous weeks are fixed there.
  • v4.2 is planned to be released at the end of this week - with DisconnectedState. Most likely, this week we'll be working mainly on Manual and fixes of issues we already know (most of them are related to samples and installer), so v4.2 Release will be almost identical to RC2 from the point of code base.
v4.2 RC2 can be found at usual download location.

Known issues: 
  • Most of issues related to v4.2 RC are still there
  • You'll be laughing: this version works fine on Oracle 9i now, but DOES NOT work on Oracle 11g. Actually we made it working well on both versions, and this was continuing until I changed the default isolation level used in DO4 to Repeatable Read (yes, now this is the default one - usage of Read Committed is more risky, so we decided to use a safer option by default). Now we get "ORA-08177: can’t serialize access for this transaction" on most of tests running at Oracle 11g (9i is fine, as well as any other DB, including PostgreSQL, that also uses MVCC!). Surely we know what this means, but since there is no any concurrent activity there, this seems completely strange. Good thing: it seems we're not alone facing this problem. So hopefully, it will be quickly resolved (we'll update RC2 installer once more after this).
That's it. Shortly I'll give few links to new tests there (they'll go to Manual soon).

February 22, 2010

Holidays...

Here are holidays again. Tomorrow is 23rd of February: Day of the Defenders of the Motherland, formerly - the Day of Soviet Army. It had never been a holiday in USSR, but now it is.

Just counted - there are 14 public paid holidays this year - so we must be among 10 countries with the most public holidays. I'm not sure why the authors of this article forgot about Russia - may be they don't know New Year holidays in Russia lasts till January 10th?

23rd of February has become a public holiday in 2002. I hate when our government employs such a primitive ways of increasing their popularity.

P.S. As you see, I decided to share some of my non-programming related thoughts in this blog. This one isn't really deep, but it describes exactly what I feel when each of such "holidays" happen - again and again. Just imagine what does it cost for economics - to sleep during 10 days in January. For all the country. No one works - even banks (btw, that's why it's simply impossible to work for many of organisations, even if they'd like to). Finally, imagine what lots of people do during this period. Celebration of New Year becomes the very last event in life for many of them.

My Google Buzz feed

About a week ago (or two? don't remember ;) ) Google Buzz have been launched, and I must say, I really like it. I tried to use Twitter before, but discovered the idea behind it (short, but frequent messages) isn't really suitable for me:
  • My ideas normally require more than 140 chars to be explained... Or. better, if I have something to say, and it fits into 140 chars, I feel most likely it doesn't worth to say it. So in short, I prefer to write a bit more detailed posts than the ones fitting into 140 chars.
  • Another issue is that I don't used to interrupt my work each 30 minutes to post something - this is simply annoying. If I really devoted to work, I can spend 60 hours nearby PC to finish it. Moreover, I work much more productively if no one interrupts me - that's one of reasons why I used to work till the deep night - the silence after 20:00 is what I like the most ;)
  • If I have something to discuss, again, I'd prefer to do this with employees first. Any ideas are normally dropped into our company-wide Skype chats first.
  • And finally, I never read my own Twitter feed completely, although I have just a handful of people I follow. I dislike the whole idea of reading tons of these tiny messages. Btw, I have ~ 100 subscriptions at Google Reader, and although I also mainly "look through" them, I read at least headers there. Hate spending the time on this as well, but... So far I don't know better way to be aware of any important news.
So in short, I dislike Twitter. That's why all of my posts there are mainly links to my blog posts.

And, as I said, nearly one week ago I started to use Buzz in GMail. I use GMail for my primary mail account, so this wasn't annoying. Moreover, it still isn't - so far I like the way Buzz works there. The only annoying thing is repeating messages about actually the same blog post. This heppen, if several persons I follow in Buzz are subscribed to the same blog.

What I like in Buzz:
  • Its ability to automatically re-publish posts from any blogs (and Twitter) in my Buzz feed. So I don't have to do this manually there.
  • Absence of 140 character limit. It reduces the body of message, if it's long - I think that's much better then these 140 chars. "Read header" - "read more".
  • An ability to use HTML in messages. Yes, I like to see the hyperlinks as I used to, as well as image thumbnails. Why I should click on something ot get some details?
  • It's really nice how Buzz deals with URLs you paste there. It automatically offers to turn them into page title (for regular web page) with hyperlink or to an image thumbnail for images. Imagine the same in Twitter...
  • Finally, Buzz automatically offered me to follow the persons I frequently interact with (friends, co-workers, etc.). There is nothing like this in Twitter, and actually absence of this feature has made me to subscribe to tweets of people I don't know personally (btw, Twitter isn't frequently used in Russia, thus I couldn't do this even if I would like to). Thus most of people I follow in Twitter aren't my friends, and I think that's bad - if so, I should be subscribed just to their regular blogs, that's it. I'm actually not interested their hourly status updates... But you know, Twitter pushes the people to make such unnecessary subscriptions. So I think the best action I can perform here is to stop following them.
That's it. To end up this post, I'd like to share my Google profile page with its Buzz feed:
My Buzz feed contains:
  • Links to all blog posts made by X-tensive.com employees.
  • Links to the articles and posts I like. I track most interesting blogs related to .NET, as well as lots of blogs related to politics and business in Russia. Thus many of shared items there are in Russian (such ones are mainly related to our politics, business and corruption).
  • I'm frequent cinema visitor (although I try to carefully choose the films to watch - I hate watching shit, it's normal I leave the film in the middle if I feel it's an example of such one), thus there are my short film reviews. Again, in Russian :)
  • Be sure, there will be no hourly status updates & absolutely silly stuff. I'll try to keep the level of such messages at minimum.

February 17, 2010

X-tensive.com is updated (warning: beta version!)

Today we've published a new (= face lifted) version of X-tensive.com. Changes there aren't dramatic, but I like the way it changed. Mainly, we touched the front page and DataObjects.Net page.

Press F5, if you feel there is something wrong - old CSS might be cached.

Note that it's a beta version, so there are lots of issues - some links from first page banner points to wrong articles; plus, there are pearls like "Localized versions of objects (January 2010)" (factual mistake: this is already implemented as Localization sample). They'll be eliminated during this week.

And, likely, you already know that on the beginning of the next week we're releasing two major updates to our products:
So stay tuned :)

DataObjects.Net v4.2 RC is available

It happened: now you can download DataObjects.Net v4.2 Release Candidate. Its reference and manual (in PDF) are available there as well.

What's new

Please refer to this post for details.

Stability

The version we've published must be quite stable - especially, for Microsoft SQL Server and PostgreSQL. I just looked up test results @ our build servers - from 0 to 2 tests fail there out of ~ 1380 in different test configurations(mapping scenarios) for these two database servers. 

So v4.2 RC is more stable than any official release we published earlier.

Known issues

Installer
  • Database creation wizard must be added for SQL Server!
Framework itself
  • Oracle support for 9i and 10g is broken in the current version (AFAIK, because of schema extractor bug), so you can use it only with Oracle 11g.
Manual
  • A set of  sections must be added, including "Versions, CC & locking", "Full-text search", etc.
Reference
  • System namespace contains classes from mscorlib.dll, but doesn't contain our own ones. Must likely this is a result of bug in Sandcastle.
  • .HxS version: all resources from Manual are missing there (images, CSS, etc.). Since .CHM version contains all these files, this can be a result of bug in Sandcastle.
Samples
  • All connection URL lists in samples must be extended to support default SQL Server Express installation and, likely, SQL Server CE database.
  • WPF Sample logo: we must provide 64x64 icon here (current one looks absolutely inacceptable in Windows 7 taskbar).
Sandbox projects

OrderAccounting project:
  • No copyright, etc. (standard header for our .cs files)
  • Thrown exceptions aren't shown
  • Default connection URL must be set to memory (likely, the same must be done for other Sandbox projects)
  • Bugs:
    - PlainWpf: Customers, Add ..., Close - error.
    - PlainWpf: Default number is 0. KeyGenerator bug, or?
    - Mvvm: error on any Add/Open action.
Nearest plans

We're going to fix most of these issues on this week (e.g. likely, the issues related to Sandcastle won't be fixed) and release v4.2 final. 

There will be minor updates related to code base as well - mainly, bugfixes, if something new will be found.

February 11, 2010

Test pass results

Test pass results

Support for connection strings and new way of setting default schema

Connection strings can be specified via provider and connectionString elements in App/Web.config files. Original approach with connection URLs is supported as well.

Example: <domain connectionString="Data Source=localhost; Integrated Security=True" name="test" provider="sqlserver" />

Notes:
  • Index storages do not support connection strings so far, since we haven't invented a syntax for them yet.
  • provider is the same string as protocol part in connection URL.

Default schema is specified via defaultSchema element.

Example: <domain connectionUrl="sqlserver://localhost/" defaultSchema="dbo" name="test"/>

Default schema can be specified with both connection strings and connection URLs. See Xtensive.Storage.Tests\App.config for various examples.

February 10, 2010

I'm back ;)

Hi everyone!

I haven't been here for a while - that's because we worked really hard to bring a set of really important changes closer to release:
  • DataObjects.Net v4.2 will be released on the next week; by the end of this week we're going to publish one more release candidate. By now, we've implemented 174 issues after the last official release (August), so it's really a big step forward. Enough to increase the number by 0.2 ;)
  • Unfortunately, I was unable to touch DisconnectedState so far, so it will be shown a bit later (v4.2.1). 
  • But there are lots of other new and really attractive features: full-text search (example queries are here) working natively at MSSQL and PostgreSQL, O2O mapping (take a look at tests for it), support for SQL Server CE, unified API for registration and activation of persistent types and services (IoC framework we use now is much more flexible; there is no dependency on Common Service Locator, but container we use is replaceable), unified storage exceptions and lots of less important improvements - e.g. much faster object removal, better KeyGenerator model.
  • I hope I'll be able to add chapters describing ASP.NET & ASP.NET MVC development with DataObjects.Net & add a bit more comprehensive samples until release. If this is done, I can fully honestly say DO4 is fully ready to be used in web applications. WPF readiness point is v4.2.1 release.
Finally, during last two weeks I did a lot of refactoring in our projects, including Xtensive.Core. I'd like to mention few nice tricks we're using now:
  • Most of extension methods to string, IEnumerable<T>, IList<T>, IDisposable<T> and few our own types are moved to System namespace, so they're visible by default now - everywhere. Really important, if you don't use a tool like ReSharper. Moreover, they're easily discoverable.
  • string.FormathWith is one of newly added methods I really like. Take a look at an example of its usage. The original idea isn't ours, but it's really brilliant.
P.S. I'll return back to regular day-to-day posts closer to release.