Tag Archives: Firebird

Hunting “EntityType ‘Image’ has no key defined. Define the key for this EntityType.” problem

Few weeks back I was hired to debug the above mentioned problem. The application was using Entity Framework 5 and Firebird as a database. The message says clearly what’s wrong. How hard can it be to fix the problem, right? I was thinking the same. And how wrong I was.

After receiving the sources and quickly extracting the bare metal with error I started looking for Image type. And there it was. The class had Id property, so the key was kind of there. The default convention should be able to find. Let’s look at configuration, if there’s something suspicious. And even better, the HasKey call is there. OK, maybe there’s some magic in OnModelCreating. Nope. Everything as expected.

By the way, the exact error was:

ModelValidationException: One or more validation errors were detected during model generation:

	System.Data.Entity.Edm.EdmEntityType: : EntityType 'Image' has no key defined. Define the key for this EntityType.
	System.Data.Entity.Edm.EdmEntitySet: EntityType: EntitySet 'Images' is based on type 'Image' that has no keys defined.

That’s the overview. Next two hours I was trying to changes something here and there and make it fail, so I knew it’s doing what it should do. Removing some stuff that might break something. And still no luck. But then something caught my eye. The error is talking about “Image” type. My type from database is “IMAGE” (the mapping and classes were generated by Entity Framework Power Tools and because of how SQL standard defines non-quoted names, it’s by default all uppercase). Yes, there was a property added to some entity that had a type Image, I mean System.Drawing.Image.

So quickly adding Ignore into OnModelCreating and I was done. Lesson learned.

Understanding (some) Firebird’s nbackup error messages (“Error (xxx) opening database file”)

Because on the server where the application is running I’m unable to do backup using regular gbak tool, I turned my attention to nbackup. In fact I’m doing just file copy and using alter database begin backup/alter database end backup (more info). But doing the backup is only part of the story. You have also know you know how to restore it and whether you can restore it (aka whether the backup is not corrupted).

If you have done backup using process described above and you have the file, you can’t just start using it. You need to “restore it”, which means changing a flag inside the database file. This is where the nbackup‘s -F switch comes to play. But no matter what I was doing, I was getting:

Failure: Error (5) opening database file: <some>.fdb

This error message is, well, completely utterly useless. While waiting for reply from firebird-support list I played with Process Monitor (of course) to see what’s wrong. But I haven’t seen any disk activity with errors. Changing paths, trying invalid paths (this produced just error 3), running 32bit version of nbackup, using one from Firebird 2.1, … And nothing. Then I decided to have a look into the ultimate documentation aka sources. It was not difficult to find piece of code:

b_error::raise(uSvc, "Error (%d) opening database file: %s", GetLastError(), dbname.c_str());

Great GetLastError. Time to jump into System Error Codes. And in no time I know it’s ERROR_ACCESS_DENIED. That’s a progress. Quick check of permissions and yes; the user I was running under had no permission to write to the file. Quickly changing that and everything was working fine.

Hope it helps somebody.

Entity Framework is open source, why not SqlClient?

If you’re watching at least a little what’s going on in .NET world you noticed that Entity Framework is open source for couple months now. That’s a good thing.

On the other had there are still some pieces of the complete stack that are not open source. The one that I’m missing most is SqlClient. I’m writing provider for Firebird and although the MSDN documentation contains a lot of content sometimes it’s not obvious how things should behave. Then the SqlClient‘s behavior is (at least by me) taken as de-facto standard. I think everybody expects behavior that adheres to it. Over the last few years I’ve spent maybe thousands of hours trying things with SqlClient and ILDASM-ing into internals. But it could be easier if you could just step into the code and see the behavior, variables, … Also other people might look at the code and instead of just reporting bug posting also related info where to find the proper implementation or how it differs internally.

I wish to go back to this post in the foreseeable future and happily strike-though the complete text and just say that SqlClient is open source too.

Custom conventions in Entity Framework 6 helping Firebird – part 2

Few days ago I wrote a post “Custom conventions in Entity Framework 6 helping Firebird“. Arthur Vickers from Entity Framework team had a good question whether it works also for columns and tables that are generated by Entity Framework (like join tables for M:N, FK columns (if not in model), etc.). And it actually does not. :) For this you have to dig a little bit deeper and use model-based convention. For this type of convention you have to write a class as there’s (currently, alpha 3) no way to do it using fluent API in a lightweight way (and I would not expect this to change, this isn’t common scenario).

Anyway for properties to work you have to implement IDbConvention<EdmProperty> and for table IDbConvention<EntityType> (not EntitySet, you need to be able to see whether somebody set the table name already or not which for me is easier from EntityType type). Don’t ask me how I found this. A lot of trial and error. And actually a lot of memories from around 2010 and Entity Framework v1 (link, link (anybody here ever explored MetadataProperties?)) :) .

class FirebirdFriendlyModelConvention : IDbConvention<EdmProperty>, IDbConvention<EntityType>
{
	public void Apply(EdmProperty dbDataModelItem, EdmModel model)
	{
		var preferredName = (string)dbDataModelItem.Annotations.First(x => x.Name == "PreferredName").Value;
		if (preferredName == dbDataModelItem.Name)
			dbDataModelItem.Name = FirebirdNamingConvention.CreateName(dbDataModelItem.Name);
	}

	EntityType GetRootType(EntityType entityType)
	{
		if (entityType.BaseType != null)
			return GetRootType((EntityType)entityType.BaseType);
		return entityType;
	}

	string GetTableName(ICollection<DataModelAnnotation> anotations)
	{
		var anotation = anotations.FirstOrDefault(x => x.Name == "TableName");
		if (anotation == null)
			return null;
		return (string)anotation.Value;
	}

	public void Apply(EntityType dbDataModelItem, EdmModel model)
	{
		var entitySet = model.Containers.First().EntitySets.SingleOrDefault(e => e.ElementType == GetRootType(dbDataModelItem));
		var tableName = GetTableName(dbDataModelItem.Annotations);
		if (tableName == null)
		{
			tableName = FirebirdNamingConvention.CreateName(dbDataModelItem.Name);
			entitySet.GetType().GetProperty("Table").SetValue(entitySet, tableName);
		}
	}
}

As you can see it’s not magic, if you know where to look at. Because the Table property is currently (alpha 3) not public I was forced to use reflection. There’s the related work item.

With this conventions, hopefully, all the tables and columns, except specified explicitly, will be renamed to “common” Firebird naming.

Custom conventions in Entity Framework 6 helping Firebird

There’s a part 2 of this story.

The next version of Entity Framework, version 6, has a nice new feature Custom Code First Conventions. In short you can create your own conventions and using these together with the default ones (these were there before). Does you primary key column/property always ends up _PK? You can create convention for that and completely remove bunch of HasKey() lines. But that’s not what I’m going to talk about, if you want to know more follow the link above.

Firebird as other databases adhering to SQL standard in naming and quotations treats unquoted column/table/… as upper case. A lot of ORMs normally quote everything, just to be safe and because it’s easier than to hunt all the exceptions and places where it might collide with reserved keywords. I’m doing that too in provider for Entity Framework for Firebird. That means, that if you create some Code First model, the SQL statements will be quoted and using default naming convention – that’s, simply speaking, same as property/class/… name. Not good. You have to write a lot of explicit HasColumnName.

But with custom conventions today, you can save your typing. Let’s say, that my naming convention is like this. Property SomeValue goes to column SOME_VALUE. So it’s upper case, words separated by underscores. In fact that’s very close to what majority of Firebird users use.

public static string CreateName(string s)
{
	return s.Aggregate(string.Empty, (acc, c) => acc + (char.IsUpper(c) && !string.IsNullOrEmpty(acc) ? "_" + c : char.ToUpperInvariant(c).ToString()), _ => _);
}

Yes, it’s a little over-LINQ-ed, but I wanted to try to write it like this. :)

The convention itself needs to implement IConfigurationConvention interface with proper mix of two generic parameters. Let’s name our columns and tables.

class FirebirdNamingConvention :
	IConfigurationConvention<PropertyInfo, PrimitivePropertyConfiguration>,
	IConfigurationConvention<Type, EntityTypeConfiguration>
{
	public static string CreateName(string s)
	{
		return s.Aggregate(string.Empty, (acc, c) => acc + (char.IsUpper(c) && !string.IsNullOrEmpty(acc) ? "_" + c : char.ToUpperInvariant(c).ToString()), _ => _);
	}

	public void Apply(PropertyInfo memberInfo, Func<PrimitivePropertyConfiguration> configuration)
	{
		var conf = configuration();
		conf.ColumnName = CreateName(memberInfo.Name);
	}

	public void Apply(Type memberInfo, Func<EntityTypeConfiguration> configuration)
	{
		var conf = configuration();
		conf.ToTable(CreateName(memberInfo.Name), null);
	}
}

Simple, isn’t it? Now we need to just register this convention.

class FirebirdContext : DbContext
{
	public FirebirdContext()
		: base(new FbConnection(@"database=localhost:test;user=sysdba;password=masterkey"), true)
	{ }

	public IDbSet<TestEntity> TestEntities { get; set; }

	protected override void OnModelCreating(DbModelBuilder modelBuilder)
	{
		modelBuilder.Conventions.Add(new FirebirdNamingConvention());
		//modelBuilder.Properties().Configure(c => c.HasColumnName(FirebirdNamingConvention.CreateName(c.ClrPropertyInfo.Name)));
		//modelBuilder.Entities().Configure(c => c.ToTable(FirebirdNamingConvention.CreateName(c.ClrType.Name)));
	}
}

I have also included other way to write the conventions, directly in OnModelCreating using so-called lightweight conventions.

Simple code to test.

Database.SetInitializer<FirebirdContext>(null);
using (var ctx = new FirebirdContext())
{
	Console.WriteLine(ctx.TestEntities.Where(x => x.MyInteger == 0).ToString());
}
class TestEntity
{
	public int Id { get; set; }
	public string SomeBoringColumn { get; set; }
	public int MyInteger { get; set; }
	public DateTime DateTime { get; set; }
	public DateTime Timestamp { get; set; }
}

And the result.

SELECT
"B"."ID" AS "ID",
"B"."SOME_BORING_COLUMN" AS "SOME_BORING_COLUMN",
"B"."MY_INTEGER" AS "MY_INTEGER",
"B"."DATE_TIME" AS "DATE_TIME",
"B"."TIMESTAMP" AS "TIMESTAMP"
FROM "TEST_ENTITY" AS "B"
WHERE 0 = "B"."MY_INTEGER"

Few lines of code and could save you maybe hundreds of lines of code you’d have to write otherwise.

Note: This code uses custom build FirebirdClient (with current stable one it will not work), because Entity Framework 6 contains some breaking changes for provider writers. I’m working on it and the test builds will be available soon.

goes to column

Error “Could not load type ‘System.Runtime.CompilerServices.ExtensionAttribute’ from assembly ‘mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089′.” on .NET 4.0/.NET 4.5

This error isn’t related only to FirebirdClient only, but any .NET application that is targeting multiple .NET Framework versions, but I spotted it first during FirebirdClient development.

The error message Could not load type 'System.Runtime.CompilerServices.ExtensionAttribute' from assembly 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. is little bit cryptic. Let me explain how all this mess happened. The .NET 4.5 is in-place update of .NET 4.0. So a lot of stuff looks like it’s .NET 4.0, but it’s not. It’s .NET 4.5. One change Microsoft did in .NET 4.5 was moving the ExtensionAttribute into mscorlib (so they can use extension methods in mscorlib). So if you build application targeting .NET 4.5 and it uses just plain .NET 4.0 (or even older) it runs fine. You’re fine, user is fine. Until it hits some extension method. Then it tries to locate the above mentioned attribute, but from mscorlib. On .NET 4.0 it’s not there. Even if the version says 4.0.0.0. Yeah, in-place update.

Problem is, that users (even some developers) are not aware of these minor changes. And because the application runs – at least a while – it’s confusing. :\ The bottom line is – always download/use exact .NET Framework version version of the application/library.