Skip to content

0005: DbMetal is(n’t) so hard… [con’t]

23/08/2010

Hello,

First, I must ask you to remember that all snippets below are test ones and won’t be contained in further versions of the OLGAtherer. Project is still in planning phase.

I’d like to continue topic from the last post and tell you about DbMetal and its automatc code generation feature. As I previously described, DbMetal had generated three files for me. First, dbml file that is, in fact, plain XML file containing information about tables and columns (and, probably, other features/dependencies for more advanced DB structures) in clear way.

I think that during actual developing process I will try to do some changes here like, for example, set other private member names (post about conventions that we will use will be published soon). For now I’m leaving it untouched.

Much more interesting is C# code file called testDbMap.cs. I’ve had many problems with it, fortunately nothing that I couldn’t overrun 🙂 We can split file on few logical parts.

First one is header that provides simple information about time that file was created and subject that data was extracted from. Next using statements follows. Note #if #else #endif directives that controls code content during compilation. In my case, I don’t develop on Mono, so code inside #if directive won’t be active (compiled).

Next partial class Main, DataContext descendant, is declared. Note that DataContext is taken from DbLinq.Data.Linq namespace, not from standard .Net Linq assembly. This part of the partial class consists of constructors only. Two most important (for me) constructors are that take connectionString or connection as parameters.

Mysterious thing is, that every ctor in its body has only one line – this.OnCreated(); If you try to find body of this method you notice, that only its header is declared, no body. So, if you open assembly in .Net Reflector tool you will see, that in fact there is nothing in these constructors, because method that is only declared doesn’t exists in compiled assembly. Constructors just invoke base class constructors, and nothing more. I don’t know what about you, but I don’t like mess in the code, so I think that during actual develop process I will ”enchant” this class a little bit by removing unnecessary lines 🙂 I’m only afraid that this code isn’t just messy, but all these strange lines are for purpose… I hope not. Maybe you could tell something more about it?

Ha, I lied about that this part of Main consists only of ctors. One property representing Books table is here also. As you can see in the examples that are attached to the source code, any table that is to be mapped will be mirrored here by the getter.

Next another #if region follows. It adds some constructors to the partial Main class depending on MONO_STRICT flag. In our case full set of ctors will be added. I wonder why partial class has been used instead of another structure of #if directives, but itsn’t so important right now. I still hope that someone will ever read it and answer to my questions 🙂

OK, next class, Books, is marked with TableAttribute and implements two interfaces (INotifyPropertyChanging and INotifyPropertyChanged) that help notifying clients. I haven’t already used them, but here I have found interesting article about one of them – I’m going to read it as soon as I finish this post 🙂

Next quite large bunch of private data members goes, set of method headers (once again they won’t be compiled) and constructor (with OnCreated() method invocation, however OnCreated method has no body, ctor will be empty anyway). What is interesting in this class, that set of setters that mirrors columns in db table “Books”. Exemplary setter would have form:

[Column(Storage="_author", Name="Author", DbType="TEXT", AutoSync=AutoSync.Never)]
          [DebuggerNonUserCode()]
           public string Author</code>

As we can see, Author property is marked by ColumnAttribute with pretty self-explanatory parameters: Storage points at private storage field, Name is the column name, DbType indicates type of data that column contains and AutoSync “Gets or sets the System.Data.Linq.Mapping.AutoSync enumeration.” Nothing special and hard to understand (surprisingly).

Next attribute – DebuggerNonUserCode. I wonder why all properties are decorated with this attribute, I think that it won’t be necessary for my purposes, and if it will make debugging harder, I will remove these attribs without hesitation.

In the body section we have get and set commands:

{
		get
		{
			return this._author;
		}
		set
		{
			if (((_author == value)
						== false))
			{
				this.OnAuthorChanging(value);
				this.SendPropertyChanging();
				this._author = value;
				this.SendPropertyChanged("Author");
				this.OnAuthorChanged();
			}
		}
	}

In the body section we have get and set command. First one works as usually – returns not affected storage field contain. Setter instead checks whether new value isn’t the same as old, if so triggers proper notification event and sets new value. Nice feature – I don’t know yet when I would use it, but I wonder whether this is connected with Observer patterns. If so, I can imagine that this feature will be very appreciated in the future works.

This is it. You may wonder why I tried to explain something that is pretty straightforward – but I think that this blog is write by young, inexperienced programmer for similar inexperienced programmers 🙂 I’m sure that I would have been very happy if someone explained this to me two days ago 🙂
OK, so let’s go to the errors that I received. Except numerous problems with making this whole set of libraries to work for me, I found two serious ones.
Take look at this snippet:

public List GetAll()
        {
            //string connString = @"Data Source=c:\test.lite;Version=3;";
            string connString = @"Data Source=c:\test.lite;";
            //IDbConnection connection = new System.Data.SQLite.SQLiteConnection(connString);

            using (Main mainDataContext = new Main(connString))
            {

                Table books1 = mainDataContext.GetTable();
                return books1.ToList();
            }

        }

Question: what will happen if connectionString will take form:
string connString = @"Data Source=c:\test.lite;Version=3;";
Answer: TargetInvocationException will be raised. “Version” keyword isn’t supported, even if this is perfectly correct connection string.

Question: what will happen then if you remove “wrong” keyword?
Answer: SqlException wil be raised. Message says that server is not configured or present.

Question: what to do then?
Answer: Change code to this one:

string connString = @"Data Source=c:\test.lite;Version=3;";
            IDbConnection connection = new System.Data.SQLite.SQLiteConnection(connString);
            using (Main mainDataContext = new Main(connection)){}

What makes the difference? I don’t know for sure, but I think that if we provide connection string, base DataContext object tries to connect with SQLite database using other provider. If we provide brand new SQLite connection, object “knows” for sure how to connect with database and won’t throw. Either way you should rather use IDbConnection than string to instantiate DataContext object.
Second issue was clearly my fault. Look at this code snippet:

Books b = mainDataContext.GetTable().First(x =&gt; x.Author == "Author");

What will happen if there will be no entity with Author field containing string “Author”? InvalidOperationException will be thrown 🙂 I must remember that while implementing db functionality.

OK, that’s really all for now 🙂 I spend too much time writing this useless words and way too little planning and coding. I can only hope that this “research” phase will yield in not so distant future 🙂
Best regards, Paweł

Advertisements
Leave a Comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: