Code through the pain Ladislav Mrnka's professional blog about software development

21Aug/113

Few week ago ADO.NET team published minor update to Entity Framework 4.1 (download page). By following ADO.NET team blog, I guess the purpose of this minor update was fixing few bugs, adding support for context factory and preparing support for Code First Migrations August 2011 CTP  which demands this update. Everything looks awesome because ADO.NET team is fixing some bugs, adding new features and working on new tools (EF power tools, migrations) and new version Entity framework. Still sometimes there can appear some unexpected problem. The mentioned update contains one annoying hidden breaking change reported by many developers using external profilers. The rest of the article will describe this problem, its impact and announced fix.

Oren Eini (Ayende @ Rahien) published the blog post about this problem in Entity Framework 4.1 Update 1. It is also discussed by Frans Bouma from LLBLGen Pro team. The problem is very simple: ADO.NET team broke backward compatibility with previous versions of Entity framework 4.1. Breaking backward compatibility is always displeasing and such change should always appear only in major versions and it should be communicated upfront and well documented. This time the breaking change is hidden inside minor update which even didn't change the assembly version. It only changed assembly file version so your code will automatically bind to this new version if you install it to GAC. Moreover the breaking change wasn't mentioned anywhere.

Another very strange fact is the content of the breaking change. The original version of the code did some comparison of assembly names to find if a database provider for the required connection is registered. I don't feel very confident about the new code used in the new version and I would really like to know why the new version doesn't compare the whole assembly version? For me this seems like some ugly hack.

The original code from EFv4.1 (assembly file version 4.1.10331.0):

public static string GetProviderInvariantName(this DbConnection connection)
{
    string assemblyQualifiedName =
        DbProviderServices.GetProviderFactory(connection).GetType().AssemblyQualifiedName;
    foreach (DataRow row in DbProviderFactories.GetFactoryClasses().Rows)
    {
        if (((string) row[3]).Equals(assemblyQualifiedName, StringComparison.OrdinalIgnoreCase))
        {
            return (string) row[2];
        }
    }
    throw Error.ModelBuilder_ProviderNameNotFound(connection);
}

The new code from EFv4.1 Update 1 (assembly file version 4.1.10715.0):

public static string GetProviderInvariantName(this DbConnection connection)
{
    Type type = connection.GetType();
    if (type == typeof(SqlConnection))
    {
        return "System.Data.SqlClient";
    }
    AssemblyName name = new AssemblyName(type.Assembly.FullName);
    foreach (DataRow row in DbProviderFactories.GetFactoryClasses().Rows)
    {
        string str = (string) row[3];
        AssemblyName name2 = new AssemblyName(str.Substring(str.IndexOf(',') + 1).Trim());
        if ((string.Equals(name.Name, name2.Name, StringComparison.OrdinalIgnoreCase) &&
            (name.Version.Major == name2.Version.Major)) &&
            (name.Version.Minor == name2.Version.Minor))
        {
            return (string) row[2];
        }
    }
    throw Error.ModelBuilder_ProviderNameNotFound(connection);
}

What this problem means to us? Every tool, code or profiler based on generic wrapping DbProviderFactory will not work with Entity Framework 4.1 Update 1 (and also Entity Framework June 2011 CTP) unless it will use some hack. Among these tools we can count:

  • EFProf from Hibernating Rhinos
  • Upcoming profiler from LLBLGen Pro

As I understand the problem, this issue should not break tools using alternative (non generic) approach to work with DbProviderFactory. For example:

  • ASP.NET MVC mini profiler

At least this is only temporary annoyance because ADO.NET team already announced fix to the problem which will be part of Entity Framework 4.2. I'm very happy to see this announcement because initial information posted on other blog posts were very disappointing - it looked like ADO.NET team is not going to fix this. That would be a big precedent in the way how Microsoft deals with backward compatibility. The announcement also described changes in the way how version numbers will be assigned to new Entity Framework releases. Because of that Entity Framework 4.2 will not be the final release of June 2011 CTP as many of us expected. It will be just the fixed release of Entity Framework 4.1 Update  1. It also declared that all new versions of Entity Framework and related tools should have a beta version to find similar problems before the product is released.

Posted on August 21, 2011 by Ladislav Mrnka
Filed under: Entity framework
Leave a comment
Comments (3) Trackbacks (0)
  1. We are working on EF code first to evaluate if it fits to our existing database. The structure of the database entites are

    1) Product (Composite Key)

    int Product ID: PK (Non Identity)- Autogenerated in Instead Of Trigger int Version From: PK (Non Identity)- Autogenerated in Instead Of Trigger

    2) Pack (Composite Key)

    PackID : PK (Non Identity)- Autogenerated in Instead Of Trigger Version From: PK (Non Identity)- Autogenerated in Instead Of Trigger Product ID: (Cannot be set as FK – Design Constraint)

    RelationShip: Product has many packs

    How can we model the above scenario with EF Code First 4.1?

    The solution which tried

    public class Product { public int ProductID { get; set; } public string ProductName { get; set; } public short Version { get; set; } public virtual ICollection Packs { get; set; } } public class Pack { public int PackID { get; set; } public int ProductID { get; set; } public short Version { get; set; } public virtual Product Product { get; set; } } public class ProductContext : DbContext { public DbSet Pack { get; set; } public DbSet Product { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Entity().ToTable(“Product”); modelBuilder.Entity().ToTable(“Pack”); modelBuilder.Entity() .HasKey(a => new { a.ProductID, a.VersionFrom }); modelBuilder.Entity() .HasKey(a => new { a.PackID, a.VersionFrom }); modelBuilder.Entity().HasMany(x => x.Packs).WithRequired().HasForeignKey(p => p.ProductID); base.OnModelCreating(modelBuilder); } } …. var product = new Product { ProductName = “EntTest1″}; var pack = new Pack {}; using (var productContext = new ProductContext()) { product.Packs.Add(pack); productContext.Product.Add(product); productContext.SaveChanges(); //**ERROR** } ….

    One or more validation errors were detected during model generation:

    System.Data.Edm.EdmAssociationConstraint: : Number of Properties in the Dependent and Principal Role in a relationship constraint must be exactly identical. Please HELP!!!

    • Please ask your question on Stack Overflow or MSDN Forums. Comments on WordPress blog are absolutely unsuitable for solving coding problems. Your question is without formatting very badly readable.

  2. Farmville farms even include free gift that fkfcegbfaeag


Leave a comment

No trackbacks yet.