Kết nối SQLite bằng Entity framework

15:00 ngày 26-10-2017

SQLite là một SQL Database Engine. Nó có thể tổ chức và quản lý dữ liệu mà không cần server. Entity framework là một framework mạnh mẽ để kết nối databse. Bài viết sẽ hướng dẫn các kết nối SQlite thông qua EF, hướng dẫn fix một số lỗi thông dụng khi làm việc.

Bước 1. Tạo Database
Bạn có thể dùng SQLiteStudio để tạo database và table.
Ở đây chúng ta tạo database: data.db3 chứa bảng Users 

CREATE TABLE `Users`
-- This table created by SQLite2009 Pro Enterprise Manager 
-- Osen Kusnadi - http://www.osenxpsuite.net 
(
       UserName VARCHAR(50),
       Name VARCHAR(50)
)

 

Bước 2. Tạo Project
Chúng ta sẽ tạo Console project để kết nối database. Project sẽ khởi tạo data cho Users table và đọc dữu liệu từ bảng Users, hiện thị đến UI.
ChọnFile/New/Project.... Trong mục Intstalled/Templates/Visual c#, chọn Console Application. Nhập tên project ConnectSqliteExample. Chọn mục Create directory for solution. Sau đó bấm OK.
Bây giờ chúng ta đã có Project mới có tên ConnectSqliteExample.

 

Bước 3. Cài thư viện SQLite vào project
Mở Manager NuGet Packages (Click chuột phải lên project). Chọn Online, sau đó search từ khóa SQLite. Chọn packages System.Data.SQLite (x86/x64) và bấm Install như bên dưới


 

Bước 4: Copy data.db3 đến project
Tạo thư mục Data trong project và copy data.db3 đã tạo ở bước 1 vào

 

Bước 5: Tạo Model và SQliteDatabaseContext để kết nối SQLite
Tạo User class trong project như sau

using System.ComponentModel.DataAnnotations;

namespace ConnectSqliteExample
{
    public class User
    {
        [Key]
        public string UserName {get; set;}
        public string Name { get; set; }
    }
}

Lưu ý: Mỗi Model phải có 1 Key. Các Column tron table ứng với Properties trong model ( phải có get; set;)

Tiếp tục tạo SQliteDatabaseContext class

using System.Data.Common;
using System.Data.Entity;
using System.Data.SQLite;

namespace ConnectSqliteExample
{
    public class SQliteDatabaseContext : DbContext
    {
        public SQliteDatabaseContext(DbConnection connection)
            : base(connection, true) 
        {
        }
        public SQliteDatabaseContext(string ConnectString) : base(new SQLiteConnection(ConnectString), true)
        {
            
        }
        public DbSet<User> Users { get; set; }
        
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
        }
    }
}

 

Bước 6: Viết Code để lưu và đọc dữ liệu từ databse
Trong file Program.cs
Chúng ta viết 2 hàm mới
InitialData: Khởi tạo 5 User nếu như bảng User là rỗng.
GetUsers: Đọc User từ bảng User

file Program.cs như sau

using System.Collections.Generic;
using System.Linq;

namespace ConnectSqliteExample
{
    class Program
    {
        static string ConnectionString = "Data Source=.\\..\\..\\Data\\data.db3;Version=3;New=False;Compress=True;UTF8Encoding=True";
        static void InitialData()
        {
            using (var context = new SQliteDatabaseContext(ConnectionString))
            {
                if (context.Users.Count() == 0)
                {
                    context.Users.Add(new User() { UserName = "UserA", Name = "Nguyen Van A" });
                    context.Users.Add(new User() { UserName = "UserB", Name = "Nguyen Van B" });
                    context.Users.Add(new User() { UserName = "UserC", Name = "Nguyen Van C" });
                    context.Users.Add(new User() { UserName = "UserD", Name = "Nguyen Van D" });
                    context.Users.Add(new User() { UserName = "UserE", Name = "Nguyen Van E" });
                    context.SaveChanges();
                }
            }
        }

        static List<User> GetUsers()
        {
            List<User> users;
            using (var context = new SQliteDatabaseContext(ConnectionString))
            {
                users = context.Users.ToList();
            }
            return users;
        }
        static void Main(string[] args)
        {
            InitialData();
            List<User> users = GetUsers();
            foreach (var user in users)
            {
                System.Console.WriteLine(string.Format("{0} - {1}", user.UserName, user.Name));
            }
            System.Console.ReadKey();
        }
    }
}

 

Vì khi chạy, file chạy sẽ ở trong thư mục Bin\Debug. Nên trong ConnectionString, đường dẫn tới file cần lui về hai cấp.

 

Bước 7: Chạy thử và fix bug :)
Thử chạy Project chúng ta sẽ gặp lỗi

An unhandled exception of type 'System.NotSupportedException' occurred in EntityFramework.dll

Additional information: Unable to determine the provider name for provider factory of type 'System.Data.SQLite.SQLiteFactory'. Make sure that the ADO.NET provider is installed or registered in the application config.

Mở File App.config. Chúng ta cần thêm

<add name="SQLite Data Provider" invariant="System.Data.SQLite" description="Data Provider for SQLite" type="System.Data.SQLite.SQLiteFactory, System.Data.SQLite" />

Trong thẻ

<system.data>
  <DbProviderFactories>
      .....
  </DbProviderFactories>
</system.data>

 Thử chạy lại, chúng ta lại gặp lỗi

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.

Tiếp tục mở App.config. Chúng ta cần thêm

<provider invariantName="System.Data.SQLite" type="System.Data.SQLite.EF6.SQLiteProviderServices, System.Data.SQLite.EF6"/>

vào thẻ 

<entityFramework>
  <providers>
      ....
  </providers>
</entityFramework>

File  App.config

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
  </configSections>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
  </startup>
  <system.data>
    <DbProviderFactories>
      <remove invariant="System.Data.SQLite.EF6" />
      <add name="SQLite Data Provider (Entity Framework 6)" invariant="System.Data.SQLite.EF6" description=".NET Framework Data Provider for SQLite (Entity Framework 6)" type="System.Data.SQLite.EF6.SQLiteProviderFactory, System.Data.SQLite.EF6" />
      <add name="SQLite Data Provider" invariant="System.Data.SQLite" description="Data Provider for SQLite" type="System.Data.SQLite.SQLiteFactory, System.Data.SQLite" />
    </DbProviderFactories>
  </system.data>
  <entityFramework>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
      <parameters>
        <parameter value="v13.0" />
      </parameters>
    </defaultConnectionFactory>
    <providers>
      <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
      <provider invariantName="System.Data.SQLite.EF6" type="System.Data.SQLite.EF6.SQLiteProviderServices, System.Data.SQLite.EF6" />
      <provider invariantName="System.Data.SQLite" type="System.Data.SQLite.EF6.SQLiteProviderServices, System.Data.SQLite.EF6"/>
    </providers>
  </entityFramework>
</configuration>

Bây giờ chạy chúng ta sẽ được kết quả như hình
  
 

Một Số Lỗi và cách fix 

An unhandled exception of type 'System.Data.Entity.ModelConfiguration.ModelValidationException' occurred in EntityFramework.dll

Additional information: One or more validation errors were detected during model generation:

Lỗi này là do thiếu khóa trên Model. Model cần được chỉ định it nhất 1 Property là khóa chính.

An unhandled exception of type 'System.Data.DataException' occurred in EntityFramework.dll

Additional information: An exception occurred while initializing the database. See the InnerException for details.

Đường dẫn đến file database là không đúng, vì vậy EF cố gắng tạo database như codefirst. Nhưng rất tiếc version hiện tại của EF chưa hổ trợ tạo SQLite. Chúng ta cần tạo database trước và chỉ định đúng đường dẫn trong ConnectionString

SQLiteException: SQL logic error or missing database no such column: Extent1.Discriminator

Extent1.Discriminator xuất hiện khi model của entity framework đang được kế thừa bởi một class khác. Để fix nó, chúng ta có 2 cách

- Sử dụng [NotMapped] trên đầu class

- Dùng modelBuilder.Ignore(); để lờ đi việc mapping class đó 

 

Link dowload Example tại đây

 

Phản Hồi

Viết Phản Hồi

Chuyên Mục

Phản Hồi Mới