Monthly Archives: March 2013

Tasks – try on retrying, loops, recursions

My mind today was in weird shape (again). I blame Friday. What that means is, that I came with weird pieces of code, that are fun to just write. Brain training. :)

The set up was simple. I had a Task that was returning bool; true if succeeded, false otherwise. Because the code was interacting with 3rd party system it was desired to retry if the call didn’t succeeded.

Looking at it in front of me I realized I’ll be probably able to (ab)use the ContinueWith method and recursion. When I wrote it I realized there’s a room for refactoring. And then I realized I might create and extension method from it. Already half way in hell. :)

public static Task<TResult> Retry<TResult>(this Func<Task<TResult>> taskMethod, Func<TResult, bool> resultOK, int retries)
{
	return taskMethod()
		.ContinueWith(t =>
			retries == 0 || resultOK(t.Result)
				? Task.FromResult(t.Result)
				: Retry(taskMethod, resultOK, --retries))
		.Unwrap();
}

Umm, how it will look like with await, I thought. Then I can use loop.

public static async Task<TResult> Retry2<TResult>(this Func<Task<TResult>> taskMethod, Func<TResult, bool> resultOK, int retries)
{
	while (true)
	{
		var result = await taskMethod();
		if (retries-- == 0 || resultOK(result))
			return result;
	}
}

This doesn’t look nice. I thought it will be smoother. This is like 90s. Back to recursion.

public static async Task<TResult> Retry3<TResult>(this Func<Task<TResult>> taskMethod, Func<TResult, bool> resultOK, int retries)
{
	var result = await taskMethod();
	return retries == 0 || resultOK(result)
		? result
		: await Retry3(taskMethod, resultOK, --retries);
}

That looks better. I don’t know whether I like the first or the third version more. But. What about performance? The second version has least code to execute. No doubt. The third version has two awaits and the recursion (nesting) with awaits. This is probably not going to be good for performance. And my tests confirms that. Slightly slower than second is the first version. Thus the winner for me is version #1. 8-)

I’m not sure why I did this (from practical perspective), but it was fun. Have a great Friday.

Changing entity names (i.e. removing prefix) in Entity Framework’s EDMX in batch

Few years back I wrote a similar post Making names of entities (or any identifiers) in Entity Framework model “code and developer friendly” (= not uppercase), but as the time goes, it’s now little bit outdated. But yesterday Julie Lerman, while trying to find solution for one particular question, dug it out. As I was also then introduced to problem the solution there was indeed a good way to go. But to use it, it needed to be updated for current version of Entity Framework (version 5 in time of writing).

So here it is. Slightly refactored. Because the question was originally interested in stripping some prefix (tbl to be precise) the code is doing exactly that. But if you want different prefix be stripped, just change the PREFIX constant. Of if you want something more change the transformation function completely (ideally should be idempotent).

static void TransformEDMXEntities(string inputFile, string outputFile)
{
	XDocument xdoc = XDocument.Load(inputFile);

	const string CSDLNamespace = "http://schemas.microsoft.com/ado/2009/11/edm";
	const string MSLNamespace = "http://schemas.microsoft.com/ado/2009/11/mapping/cs";
	const string DesignerNamespace = "http://schemas.microsoft.com/ado/2009/11/edmx";
	XElement csdl = xdoc.Descendants(XName.Get("Schema", CSDLNamespace)).First();
	XElement msl = xdoc.Descendants(XName.Get("Mapping", MSLNamespace)).First();
	XElement designerDiagram = xdoc.Descendants(XName.Get("Designer", DesignerNamespace)).First();

	Func<string, string> transformation = (string input) =>
	{
		const string PREFIX = "tbl";
		Regex re = new Regex(string.Format(@"{0}(\w+)", Regex.Escape(PREFIX)), RegexOptions.None);
		return re.Replace(input, new MatchEvaluator(
			(Match m) =>
			{
				return m.Groups[1].Value;
			}));
	};

	TransformCSDL(CSDLNamespace, csdl, transformation);
	TransformMSL(MSLNamespace, msl, transformation);
	TransformDesigner(DesignerNamespace, designerDiagram, transformation);

	using (XmlTextWriter writer = new XmlTextWriter(outputFile, Encoding.Default))
	{
		xdoc.WriteTo(writer);
	}
}

static void TransformDesigner(string DesignerNamespace, XElement designerDiagram, Func<string, string> transformation)
{
	foreach (var item in designerDiagram.Elements(XName.Get("EntityTypeShape", DesignerNamespace)))
	{
		item.Attribute("EntityType").Value = transformation(item.Attribute("EntityType").Value);
	}
}

static void TransformMSL(string MSLNamespace, XElement msl, Func<string, string> transformation)
{
	foreach (var entitySetMapping in msl.Element(XName.Get("EntityContainerMapping", MSLNamespace)).Elements(XName.Get("EntitySetMapping", MSLNamespace)))
	{
		entitySetMapping.Attribute("Name").Value = transformation(entitySetMapping.Attribute("Name").Value);
		foreach (var entityTypeMapping in entitySetMapping.Elements(XName.Get("EntityTypeMapping", MSLNamespace)))
		{
			entityTypeMapping.Attribute("TypeName").Value = transformation(entityTypeMapping.Attribute("TypeName").Value);
		}
	}
}

static void TransformCSDL(string CSDLNamespace, XElement csdl, Func<string, string> transformation)
{
	foreach (var entitySet in csdl.Element(XName.Get("EntityContainer", CSDLNamespace)).Elements(XName.Get("EntitySet", CSDLNamespace)))
	{
		entitySet.Attribute("Name").Value = transformation(entitySet.Attribute("Name").Value);
		entitySet.Attribute("EntityType").Value = transformation(entitySet.Attribute("EntityType").Value);
	}
	foreach (var associationSet in csdl.Element(XName.Get("EntityContainer", CSDLNamespace)).Elements(XName.Get("AssociationSet", CSDLNamespace)))
	{
		foreach (var end in associationSet.Elements(XName.Get("End", CSDLNamespace)))
		{
			end.Attribute("EntitySet").Value = transformation(end.Attribute("EntitySet").Value);
		}
	}

	foreach (var entityType in csdl.Elements(XName.Get("EntityType", CSDLNamespace)))
	{
		entityType.Attribute("Name").Value = transformation(entityType.Attribute("Name").Value);
	}
	foreach (var association in csdl.Elements(XName.Get("Association", CSDLNamespace)))
	{
		foreach (var end in association.Elements(XName.Get("End", CSDLNamespace)))
		{
			end.Attribute("Type").Value = transformation(end.Attribute("Type").Value);
		}
	}
}

When you (re)generate your EDMX file, you can unleash this code (I think simple console app will be best for it), do the transformation and reopen the file in Visual Studio. If the transformation is idempotent you’re ready to go, else you’ll need to do some manual merging with previous version.

Of course you can go further and change also names on i.e. navigational properties and so on. In fact in original post in comments you can find inspiration for it.

Enjoy.

Custom transactions in Entity Framework 6

Entity Framework 6 will come with a nice feature of being able to use custom transactions. You can either manually start new one with some isolation level (in fact this was possible even before, just little bit more code) or – and this is really nice, because I had questions about this (and did some custom hacks in Firebird’s provider) couple of times. So I like it. And I like it also because finally the transactions are (at least in my eyes) of same importance as connections (where the support was good before).

There’s one thing, I think, that will make it even better. Something like “transaction factory”. The motivation behind is, that you often need to have a specific set up for the transactions and use it always (with maybe few exceptions). The UseTransaction method seems to have one drawback: you need to access the connection (that means either from context or from other place where you stored it) and start the transaction. Later commit or rollback it. You can do it easily for SaveChanges/SaveChangesAsync. But for queries? You’ll need to create and use your own plumbing/infrastructure throughout the code. But adding some point, where you can plug in (and also though resolver/configuration), might make it very easy.

// i.e. Func<DbConnection, DbTransaction>
dbContextInstance.TransactionFactory = connection => (connection as MyDbConnection).BeginTransaction(/* some crazy setup */);  // MyDbConnection is the actual store connection

Of course, you might say: “And who is going to commit/rollback it?”. You might opt-in for default behavior – no error = commit, rollback else. Or handle it manually in some OnCommit/OnRollback events (or factory again to make it more enterprise-ish 8-)).

Anyway I don’t want to discuss all the details of actual implementation or how it aligns to current state. Just a opinion and high level overview of my thoughts.

If you might have questions or need some examples or motivations, let me know in comments. I have handful of these.

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

String splitting and ordering enlightenment

Couple of years back I wrote a C# that was splitting response from server to lines. I had the data as one string and I needed to have it as array of strings, based on lines. Pretty simple, right?

The code I wrote was basically this.

response.Split(new[] { "\r", "\n", "\r\n" }, StringSplitOptions.None);

And it was working fine. Until yesterday. The server part of the solution was moved to new machine and new language. And now it started returning the exact same string, except for new lines. Now the line endings were \r\n, standard on Windows. Without too much thinking you immediately realize, the code above still works, but splits “too much”.

Of course, the fix was easy, just changing the order, having \r\n first.

Silly me. Still learning.