2

I would like to implement a custom database initialization strategy so that I can:

  • generate the database if not exists
  • if model change create only new tables
  • if model change create only new fields without dropping the table and losing the data.

Thanks in advance

Shakeeb Ahmed
  • 1,778
  • 1
  • 21
  • 37

3 Answers3

2

You need to implement IDatabaseInitializer interface.

Eg

public class MyInitializer : IDatabaseInitializer<MyDbContext>
{
    public void InitializeDatabase(MyDbContext context)
    {
        //your logic here
    }
}

And then set your initializer at your application startup

Database.SetInitializer<ProductCatalog>(new MyInitializer());

Here's an example

You will have to manually execute commands to alter the database.

context.ObjectContext.ExecuteStoreCommand("ALTER TABLE dbo.MyTable ADD NewColumn VARCHAR(20) NULL");

You can use a tool like SQL Compare to script changes.

Eranga
  • 32,181
  • 5
  • 97
  • 96
  • I know that I have to implement IDatabaseInitializer I want to know how to have the three points I have mention in the question. – Shakeeb Ahmed Jul 16 '11 at 23:46
  • @PeachLabs there is no easy way to implement your last 2 points. You are better off with other database tools – Eranga Jul 16 '11 at 23:52
  • what database tools and also I want to achieve this progammatically, if I have to release a new version of my app then I will lose data in the database. – Shakeeb Ahmed Jul 17 '11 at 01:24
  • @PeachLabs edited my answer. AFAIK you have to manually execute statements to change the database – Eranga Jul 17 '11 at 01:52
2

There is a reason why this doesn't exist yet. It is very complex and moreover IDatabaseInitializer interface is not very prepared for such that (there is no way to make such initialization database agnostic). Your question is "too broad" to be answered to your satisfaction. With your reaction to @Eranga's correct answer you simply expect that somebody will tell you step by step how to do that but we will not - that would mean we will write the initializer for you.

What you need to do what you want?

  • You must have very good knowledge of SQL Server. You must know how does SQL server store information about database, tables, columns and relations = you must understand sys views and you must know how to query them to get data about current database structure.
  • You must have very good knowledge of EF. You must know how does EF store mapping information. You must be able to explore metadata get information about expected tables, columns and relations.
  • Once you have old database description and new database description you must be able to write a code which will correctly explore changes and create SQL DDL commands for changing your database. Even this look like the simplest part of the whole process this is actually the hardest one because there are many other internal rules in SQL server which cannot be violated by your commands. Sometimes you really need to drop table to make your changes and if you don't want to lose data you must first push them to temporary table and after recreating table you must push them back. Sometimes you are doing changes in constraints which can require temporarily turning constrains off, etc. There is good reason why tools which do this on SQL level (comparing two databases) are probably all commercial.

Even ADO.NET team doesn't implemented this and they will not implement it in the future. Instead they are working on something called migrations.

Edit:

That is true that ObjectContext can return you script for database creation - that is exactly what default initializers are using. But how it could help you? Are you going to parse that script to see what changed? Are you going to execute that script in another connection to use the same code as for current database to see its structure?

Yes you can create a new database, move data from the old database to a new one, delete the old one and rename a new one but that is the most stupid solution you can ever imagine and no database administrator will ever allow that. Even this solution still requires analysis of changes to create correct data transfer scripts.

Automatic upgrade is a wrong way. You should always prepare upgrade script manually with help of some tools, test it and after that execute it manually or as part of some installation script / package. You must also backup your database before you are going to do any changes.

Ladislav Mrnka
  • 360,892
  • 59
  • 660
  • 670
  • I dont want someone to write for me if you work with ObjectContext there is a function which return the SQL which you can use to create the database. But if I update my model there is no mean I can update the database wihtout losing the previous data. – Shakeeb Ahmed Jul 18 '11 at 04:07
  • Agreed on this, tell me one more thing do you have any idea how to implement a plug-in architecture in mvc3. – Shakeeb Ahmed Jul 18 '11 at 08:48
  • Plugin architecture in MVC is separate question: http://stackoverflow.com/questions/340183/plug-in-architecture-for-asp-net-mvc – Ladislav Mrnka Jul 18 '11 at 09:50
  • In such case I suggest you to check Orchard. – Ladislav Mrnka Jul 18 '11 at 16:06
  • I actually think this is a pretty straight forward question and it should also be an easy problem to solve for Microsoft. They already have similar functionality in SSMS, Access etc. I think your response is rather negative too. – Jonesie Dec 31 '11 at 18:53
  • @Jonesie: If you believe it is an easy problem to solve you can start your open source project and prove it. That is not an easy. EF Migrations are under development (by MS) more then one year and they are still only in CTP. Neither SSMS or Access have asked functionality even on database level and in this case it is not on database level. At this point it looks more like either I don't understand your comment or you probably don't see the complexity behind the asked question. – Ladislav Mrnka Dec 31 '11 at 20:41
  • I didn't say it was easy for anyone, I said it should be easy for Microsoft. They have the brainy people and the budget to do it. EF Migrations looks pretty good but I already have a simpler, less elegant solution in a custom data layer that upgrades database schemas for SQL Server and SQL CE databases. Wrapping this in an initializer would be trivial. Sorry, no, you cant have that, I charge for my time, but my opinionated opinions are free :) – Jonesie Jan 01 '12 at 17:27
  • @Jonesie: And that is the whole problem. Do not overestimate money and resources companies like MS put into development. – Ladislav Mrnka Jan 01 '12 at 18:14
2

The best way to achieve this is probably with migrations:

http://nuget.org/List/Packages/EntityFramework.SqlMigrations

Good blog posts here and here.

Tom Wadley
  • 121,983
  • 1
  • 26
  • 29