Monthly Archives: May 2009

FirebirdClient 2.5 Final released

I’m happy to announce, after about 47 000 000 seconds of thinking and development, release of FirebirdClient 2.5. This new shiny release contains couple of very interesting new features:

  • Implementation of Firebird 2.1 protocol improvements. These improvements are focused on making the communication more efficient on slow and with high latencies networks like the internet.
  • Entity Framework support. Entity Framework is new, rich OR mapping and modeling tool, sitting on the top of ADO.NET. It is store agnostic, using ADO.NET provider to work smoothly, and the FirebirdClient has now build-in support for it.
  • Windows integrated auth. Firebird server is now able on Windows to authenticate users using a system (ActiveDirectory, etc.), and when you omit username and password FirebirdClient will try to negotiate with server this kind of authentication.
  • Timeout for wait transactions.

Of course, this release contains also lot of bug fixes and performance improvements. You can see the most important on http://tracker.firebirdsql.org/sr/jira.issueviews:searchrequest-printable/temp/SearchRequest.html?&pid=10003&fixfor=10170&fixfor=10340&fixfor=10261&fixfor=10240&fixfor=10230&status=5&status=6&sorter/field=issuekey&sorter/order=DESC&tempMax=1000. I’m also happy to say, that we have again full set of builds available for download. You can download build for .NET 3.5 (and unit tests), .NET 2.0, Compact Framework, Mono (Linux build) and also ASP.NET web providers.

One of the early adopters, SMS-Timing, of Entity Framework support for Firebird comments:
“Thanks to Jiri’s (link) work the Firebird .NET Data Provider made a lot of progress and is now even supporting the Entity Framework. Because of the adaptations we were able to use the newest .NET technologies in a modern programming environment together with a well known Firebird Database. In our industry (entertainment) the customers expect new and exciting software, and therefore the development tools need to be cutting edge. These developments in Firebird have a big impact on our products, and we hope that it brings the same boost to the Firebird Community itself. A preview of our newest software: www.fast4thefuture.com, http://www.sms-timing.com/en/software_kiosk.php.”

You can download the new version on http://www.firebirdsql.org/index.php?op=files&id=netprovider.

is, as, != null

Po diskuzi v postu if, else, return jsem si uvědomil, že mám v kapse ještě jeden případ, který je podobně sporný-zajímavý. Tyto dvě konstrukce vídávám a opět v zásadě stejné – nebo ne?

Foo x = (y as Foo);
if (x != null)
{
  x...
}
else
{
  // <error>
}

resp. (samozřejmě můžeme i přiřadit do x)

if (y is Foo)
{
  (y as Foo)...
}
else
{
  // <error>
}

Osobně používam druhý způsob, opět spíše pocitově něž pro nějaký fakt (myslím, že z toho is je výsledek mého snažení lépe čitelný). A co vy? Případně máte nějaký argument proč používat jedno nebo druhé?

IsGraphDirty method

Probably one of the first methods you’ve seen/wrote while playing with Entity Framework is IsDirty method. It’s a great example how to use ObjectStateManager. While doing consultancy work I was asked to create method IsGraphDirty. Handy if you have i.e. some editing form with couple of related entities like Order and OrderLines.

The problem itself can be divided into three parts. First you’ll check the entity itself, of course. Then all the related enties and finally all the associations. Why the associations?

The associations are first class citizens in EF. And when you i.e. assign one OrderLine to different Order, then the association is changed (in fact added and deleted), not the OrderLine (in database the OrderLine will be changed, but you’re not thinking in behavior of store).

The method below is using exactly this way. When first dirty element is found, false is returned. Method is storing already checked entities in a collection to avoid spinning in a circle.

private static IEnumerable<ObjectStateEntry> GetObjectStateEntries(this ObjectStateManager osm)
{
    return osm.GetObjectStateEntries(EntityState.Added | EntityState.Deleted | EntityState.Modified | EntityState.Unchanged);
}

private static bool IsModifiedEntityModified(this ObjectStateManager osm, EntityObject entity)
{
    if (entity.EntityState != EntityState.Modified)
        throw new ArgumentException("Entity isn't modified.");

    ObjectStateEntry ost = osm.GetObjectStateEntry(entity);
    for (int i = 0; i < ost.OriginalValues.FieldCount; i++)
    {
        object original = ost.OriginalValues.GetValue(i);
        object current = ost.CurrentValues.GetValue(i);
        if (!original.Equals(current))
            return true;
    }
    return false;
}

public static bool IsDirty(this ObjectContext context, EntityObject entity)
{
    return
        (entity.EntityState == EntityState.Added)
        ||
        (entity.EntityState == EntityState.Deleted)
        ||
        (entity.EntityState == EntityState.Modified && context.ObjectStateManager.IsModifiedEntityModified(entity));
}

public static bool IsDirty(this EntityObject entity, ObjectContext context)
{
    return context.IsDirty(entity);
}

One of the improvements that’s left, is to save also the associations checked, to avoid checking it twice and thus (maybe) finish sooner. Another may be to rewrite it without recursion.

I’m using there couple of other helper methods.

private static IEnumerable<ObjectStateEntry> GetObjectStateEntries(this ObjectStateManager osm)
{
    return osm.GetObjectStateEntries(EntityState.Added | EntityState.Deleted | EntityState.Modified | EntityState.Unchanged);
}

private static bool IsModifiedEntityModified(this ObjectStateManager osm, EntityObject entity)
{
    if (entity.EntityState != EntityState.Modified)
        throw new ArgumentException("Entity isn't modified.");

    ObjectStateEntry ost = osm.GetObjectStateEntry(entity);
    for (int i = 0; i < ost.OriginalValues.FieldCount; i++)
    {
        object original = ost.OriginalValues.GetValue(i);
        object current = ost.CurrentValues.GetValue(i);
        if (!original.Equals(current))
            return true;
    }
    return false;
}

public static bool IsDirty(this ObjectContext context, EntityObject entity)
{
    return
        (entity.EntityState == EntityState.Added)
        ||
        (entity.EntityState == EntityState.Deleted)
        ||
        (entity.EntityState == EntityState.Modified && context.ObjectStateManager.IsModifiedEntityModified(entity));
}

public static bool IsDirty(this EntityObject entity, ObjectContext context)
{
    return context.IsDirty(entity);
}

The IsModifiedEntityModified method is checking whether the entity has been "really" modified. I.e. you can change some values and then change it back. The entity is marked as modified, but you may not to consider it as modified (depends on you needs). Anyway you can remove it form IsDirty and the code will work fine.

The last couple of methods are extension methods taken from Danny Simmons's post with handy methods, just to make my life easier.

private static bool IsRelationshipForKey(this ObjectStateEntry entry, EntityKey key)
{
    if (!entry.IsRelationship)
        throw new ArgumentException("Entry isn't for relationship.");

    return ((EntityKey)entry.UsableValues()[0] == key) || ((EntityKey)entry.UsableValues()[1] == key);
}

private static IExtendedDataRecord UsableValues(this ObjectStateEntry entry)
{
    switch (entry.State)
    {
        case EntityState.Added:
        case EntityState.Detached:
        case EntityState.Unchanged:
        case EntityState.Modified:
            return (IExtendedDataRecord)entry.CurrentValues;
        case EntityState.Deleted:
            return (IExtendedDataRecord)entry.OriginalValues;
        default:
            throw new InvalidOperationException("This entity state should not exist.");
    }
}

private static EntityKey OtherEndKey(this ObjectStateEntry relationshipEntry, EntityKey thisEndKey)
{
    if ((EntityKey)relationshipEntry.UsableValues()[0] == thisEndKey)
    {
        return (EntityKey)relationshipEntry.UsableValues()[1];
    }
    else if ((EntityKey)relationshipEntry.UsableValues()[1] == thisEndKey)
    {
        return (EntityKey)relationshipEntry.UsableValues()[0];
    }
    else
    {
        throw new InvalidOperationException("Neither end of the relationship contains the passed in key.");
    }
}

if, else, return

Občas vidím ve zdrojácích funkce s konstrukcí:

if (<condition>)
{
  x = DoSomething(y);
  return x;
}
return z;

Což je víceméně to samé jako:

if (<condition>)
{
  x = DoSomething(y);
  return x;
}
else
{
  return z;
}

Osobně používám druhý zápis. Přijde mi o něco přehlednější a explicitnější. Pravděpodobně vliv Delphi/ObjectPascalu.

Je však v těchto zápisech nějaký rozdíl? Nějaký praktický aspekt, který mi uniká?

What the hell, where’s my added view?

This behavior may confuse you. You’re adding new shiny view and it’s not added into the model. Where’s the problem?

Well the problem is caused by the fact, that every object in EDM has (must have) key (EntityKey). And because usually you have no one on view the view is added but it’s commented out. Hence if you open your EDMX file in XML editor, you’ll see the comment and you can uncomment it. The designer is trying to infer the key from not null columns, but that’s may not be true in your case. Thus you may need to edit selected columns in <Key> (CSDL) element. Then save and you’re done. You can use the view in your model.

C# obsesión – how many characters you are able to put into type? :)

I was writing some return type from function when I got brilliant dumb idea to start playing with braces, question marks etc. :) And I came with some self-competition to write a lot of different characters into a valid type definition (in C#, of course). And simple repeating doesn’t count. But why not to create this as a public competition. ;)

With the short first try I ended up with this:

IEnumerable<KeyValuePair<int, int?>?[,]>

That’s probably not the best what can be done. Do you have better idea? OK, it’s your turn. Use comments. The best – I’m the referee – will get the lolipop.

Sorry for all spanish speaking people if the word in title isn’t right.