博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
SQLITE WITH ENTITY FRAMEWORK CODE FIRST AND MIGRATION
阅读量:6709 次
发布时间:2019-06-25

本文共 10286 字,大约阅读时间需要 34 分钟。

Last month I’ve a chance to develop an app using Sqlite and Entity Framework Code First. Before I started with this project, I thought everything will be easy because Sqlite and Entity Framework are both popular framework. Maybe I just need to install some nuget packages and it will work like a charm. But… yes, there is always a ‘but’ later, it’s just not so easy. Especially when I usually work with NHibernate than Entity Framework. The installation doesn’t complete his job when configuring the .config file (or maybe it just happens for me or does the author do it with intentionally?) and the Migration for Sqlite Entity Framework Code First is not supported (please correct me if I’m wrong). There are, of course, commercial products for Sqlite Migration but I prefer an open source framework or something free :). So in this post I would like to write down the steps required when starting a project for Sqlite Entity Framework Code First and how I make my own simple Migration engine.

 

1. Prerequisites

– I will use same example at this previous post . I recommend you to read that post first before starting with this one if you don’t have any experience with Entity Framework Code First. That post is very informative for beginner.

– Starting with Visual Studio 2012, NuGet is included in every edition (except Team Foundation Server) by default. So if you’re using Visual Studio 2010 and still don’t have NuGet then read this post at section 1.2 for

2. Install and configure Sqlite with Entity Framework Code First

– Create a Console project in Visual Studio

– Right click on your project and choose Manage NuGet Packages…

Manage NuGet Packages...

– On new opened dialog be sure that you’re in Online –> nuget.org section

Online nuget.org

– In text box Search Online, enter sqlite and install the package you want. For example in my demo I usedSystem.Data.SQLite (x86/x64)

System.Data.SQLite (x86/x64) NuGet package

– In App.config file, declare our connection string like this

1
2
3
<
connectionStrings
>
    
<
add
name
=
"CourseraContext"
connectionString
=
"Data Source=|DataDirectory|Coursera.sqlite"
providerName
=
"System.Data.SQLite.EF6"
/>
  
</
connectionStrings
>

– In section, edit your invariant by adding .EF6 after it

Sqlite invariant

– The default settings from NuGet packages won’t work. If you let the settings as default, you’ll get an error like this

An unhandled exception of type ‘System.InvalidOperationException’ occurred in EntityFramework.dll

Additional information: No Entity Framework provider found for the ADO.NET provider with invariant name ‘System.Data.SQLite’. Make sure the provider is registered in the ‘entityFramework’ section of the application config file. See http://go.microsoft.com/fwlink/?LinkId=260882 for more information.

– Therefore you either remove all suffixes .EF6 from your settings or add this suffix .EF6 to invariant like I suggest above.

3. Create and access database Sqlite

– Unlike MS SQL Server, as default, the free Sqlite driver from https://system.data.sqlite.org doesn’t support Migration so we can’t create a new database from code, we have to manually create it. You can use any tool you have to create a Sqlite database, I suggest using SQLite Manager add-on for Firefox. It’s easy to install, easy to use and very stable.

https://addons.mozilla.org/en-US/firefox/addon/sqlite-manager/

– After installing the add-on, create a new database and add two tables as image below (what we’re doing is not “really Code First” because we have to create database ourselves but I would like to illustrate how Entity Framework for Sqlite works so just accept this solution)

SQLite Manager

– In your Visual Studio project, create 2 contract classes for two tables in your SQLite database

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
internal
class
Course
{
    
public
int
Id {
get
;
set
; }
 
    
public
string
Name {
get
;
set
; }
 
    
public
string
Url {
get
;
set
; }
 
    
public
virtual
List Students {
get
;
set
; }
}
 
class
Student
{
    
public
int
Id {
get
;
set
; }
 
    
public
string
FirstName {
get
;
set
; }
 
    
public
string
LastName {
get
;
set
; }
 
    
public
int
CourseId {
get
;
set
; }
 
    
public
virtual
Course Course {
get
;
set
; }
}

– Create a context derived from DbContext for querying data into our contract classes

1
2
3
4
5
internal
class
CourseraContext : DbContext
{
    
public
DbSet<Course> Courses {
get
;
set
; }
    
public
DbSet<Student> Students {
get
;
set
; }
}

– As I mentioned above we’ll build same example as previous post, so the code are exactly same as another. The only difference is in connectionString in App.config above, the code for getting/setting data is also same

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private
static
void
EnterCourse()
{
    
string
name =
""
;
 
    
while
(name !=
"0"
)
    
{
        
Console.WriteLine(
"Enter name of course (0 to exit):"
);
        
name = Console.ReadLine().Trim();
        
if
(name !=
"0"
)
        
{
            
using
(
var
db =
new
CourseraContext())
            
{
                
Course course =
new
Course();
                
course.Name = name;
                
db.Courses.Add(course);
                
db.SaveChanges();
            
}
        
}
    
}
}

– Start your console application and enter some data for course and students. Verify the existing of the data with SQLite Manager and we’re finished with the first part about installing and configuring Sqlite Entity Framework.

4. Migration

– In previous part, I showed you how to make Sqlite Entity Framework “Code First” working with an available database. It’s pretty simple and easy, except that we have to reconfigure the settings in App.config file. However, as we all know, the Sqlite driver for Entity Framework doesn’t support Migration. When we make changes to our value objects, we have to update the database ourselves outside of the application, be sure that everything correct before connecting our new version to the updated database.

– There are some commercial products out there for Sqlite Migration engine which is expected to work wonderfully like the default one for MS Sql Server. However I think that we can use the same concept for database management used in Android for creating our own simple Migration engine. In Android there is a class called SQLiteOpenHelper to manage database creation and version management. I will try to make a same thing like that class. However because of keeping thing simple as it is, I skip the database creating section. My class only checks the current version of database and executes the SQL queries for updating the database if necessary.
– Back to our demo, in the first part we have to create 2 tables for Course and Student in SQLite Manager and connect to them later with our code. With new Migration engine, we only have to create a template of database (which can be used later for any application). This template is just a blank Sqlite database with a predefined table SchemaInfoes like image below

Database struture with migrations

– This table SchemaInfoes is used for storing current version of database. In combination with Helper class in code, we will make the Migration on the fly when program runs. In this demo, I will create 2 tables Courses and Students on run-time. In Visual Studio project, let’s create a new DbContext calledCourseraContextMigration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class
CourseraContextMigration : DbContext
{
    
public
static
int
RequiredDatabaseVersion = 1;
 
    
public
DbSet<Course> Courses {
get
;
set
; }
 
    
public
DbSet<Student> Students {
get
;
set
; }
 
    
public
DbSet<SchemaInfo> SchemaInfoes {
get
;
set
; }
 
    
public
void
Initialize()
    
{
        
using
(CourseraContextMigration courseraContext =
new
CourseraContextMigration())
        
{
            
int
currentVersion = 0;
            
if
(courseraContext.SchemaInfoes.Count() > 0)
                
currentVersion = courseraContext.SchemaInfoes.Max(x => x.Version);
            
CourseraContextHelper mmSqliteHelper =
new
CourseraContextHelper();
            
while
(currentVersion < RequiredDatabaseVersion)
            
{
                
currentVersion++;
                
foreach
(
string
migration
in
mmSqliteHelper.Migrations[currentVersion])
                
{
                    
courseraContext.Database.ExecuteSqlCommand(migration);
                
}
                
courseraContext.SchemaInfoes.Add(
new
SchemaInfo() { Version = currentVersion });
                
courseraContext.SaveChanges();
            
}
        
}
 
    
}
}

The static variable RequiredDatabaseVersion indicates that the version of database must be (or at least must be) so that the current version of application can connect to. In our demo, we would like to say “Ok, now we are on version 1, let’s update the database to that version”. The DbSet<Course> and DbSet<Student> is same as before for storing data from database. What’s new in this DbContext are DbSet<SchemaInfo> and Initialize()function. The Initialize() function will check the current version of database, if it’s smaller than the required version, the CourseraContextHelper() will come into use by executing the predefined SQL queries to update the database structure.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class
CourseraContextHelper
{
    
public
CourseraContextHelper()
    
{
        
Migrations =
new
Dictionary<
int
, IList>();
 
        
MigrationVersion1();
    
}
 
    
public
Dictionary<
int
, IList> Migrations {
get
;
set
; }
 
    
private
void
MigrationVersion1()
    
{
        
IList steps =
new
List();
 
        
steps.Add(
"CREATE TABLE \"Courses\" (\"Id\" INTEGER PRIMARY KEY  AUTOINCREMENT  NOT NULL , \"Name\" TEXT, \"Url\" TEXT)"
);
        
steps.Add(
"CREATE TABLE \"Students\" (\"Id\" INTEGER, \"FirstName\" TEXT, \"LastName\" TEXT, \"CourseId\" INTEGER)"
);
 
        
Migrations.Add(1, steps);
    
}
}

– In our demo, what we need is the two tables for Courses and Students for Version 1. Therefore inMigrationVersion1(), I add two queries for creating these tables and register these steps for version 1 in property Migrations. When your application is already at customer and you have changes in your database. Just make another functions for version 2, 3, 4… with your changes reflected in SQL queries and then register them in property Migrations.  Sqlite is usually for a mini-database application so, in principle, you won’t have two many migrations to manage here.

5. Conclusion

– Entity Framework is a powerful framework for working with database. There are a lot of drivers supporting many different database platforms, such as  MS Sql, Sqlite, MySQL, Oracle… The installation and configuration is pretty afloat. The Migration is not available for some drivers but we can use the concept like Android to make our simple Migration engine which can be applied for any database platform.

– The soure code of demo can be checked out or downloaded from following link

转载地址:http://dxilo.baihongyu.com/

你可能感兴趣的文章
TensorFlow实现线性回归
查看>>
Python 类的一些BIF
查看>>
C#之Socket的简单使用
查看>>
P4211[BZOJ 3626] [LNOI2014]LCA
查看>>
bzoj3993: [SDOI2015]星际战争(二分+最大流)
查看>>
CentOS-6 yum安装nginx php53 mysql55 搭建LNMP环境
查看>>
利用a标签下载,中文乱码
查看>>
hackthebox通关手记(持续更新)
查看>>
js实现过滤重复字符和重复数组-javascript技巧
查看>>
docker 镜像导入导出[转]
查看>>
linux nvme的那些workqueue
查看>>
hihoCoder 1513 小Hi的烦恼
查看>>
算法图解之大O表示法
查看>>
word2vec模型cbow与skip-gram的比较
查看>>
C语言使用 void 指针实现栈模板
查看>>
Mysql中Join用法及优化
查看>>
Django 路由系统
查看>>
3.1 特性
查看>>
ProtectData
查看>>
Keras AttributeError 'NoneType' object has no attribute '_inbound_nodes'
查看>>