I have written, IMHO, a better implementation for
Working with SQLite in C# & VB[
^] that does a lot more. It's been used in a number of commercial apps.
With the library from my article, the
DbContext
has an
Exists
method for checking if the DB exists and a
CreateDB
method for creation. Or you can use the
DbRegistry
wrapper class that has an
AutoCreate
option when attaching one or more
DbContexts
- ref:
Other Database Functions section[
^].
However, these days, I like to use
Entity Framework Core[
^] and it is quite easy to use.
Here is a sample for EF CORE in a winforms app with auto DB creation:
Part A - Models
A-1. Base
EntityObject
public interface IEntityObject
{
long Id { get; set; }
}
public abstract class EntityObject : IEntityObject
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public virtual long Id { get; set; }
}
A-2
PersonDTO
model:
public class PersonDTO : EntityObject
{
public PersonDTO
(
string firstName,
string lastName,
string? email = null,
string? gender = null,
string? phone = null)
{
FirstName = firstName;
LastName = lastName;
Email = email ?? "";
Gender = gender ?? "";
Phone = phone ?? "";
}
[JsonPropertyName("first_name")]
public string FirstName { get; set; }
[JsonPropertyName("last_name")]
public string LastName { get; set; }
[JsonPropertyName("email")]
public string Email { get; set; }
[JsonPropertyName("gender")]
public string Gender { get; set; }
[JsonPropertyName("phone")]
public string Phone { get; set; }
}
NOTE: I am pulling data from a JSON file, so all properties have property name mappings.
Part B - DataBase using EF CORE
B-1. DTO Model Configuration
B-1a.
EntityTypeConfiguration<T>
Base Configuration - for use with any DTO configuration:
public class EntityTypeConfiguration<TEntity> : IEntityTypeConfiguration<TEntity>
where TEntity : class
{
#region Constructor
public EntityTypeConfiguration() { }
#endregion
#region Properties
#endregion
#region Methods
public virtual void Configure(EntityTypeBuilder<TEntity> builder)
{
const string DefaultSql = "DATETIME('now')";
builder.Property<DateTime>("Created")
.IsRequired()
.ValueGeneratedOnAdd()
.HasDefaultValueSql(DefaultSql);
builder.Property<DateTime>("LastUpdated")
.IsRequired()
.ValueGeneratedOnAddOrUpdate()
.HasDefaultValueSql(DefaultSql);
}
#endregion
}
Here we are automatically adding
Created
&
LastUpdated
columns to every table.
B-1b.
PersonConfiguration
- adding indexes to tables
public class PersonConfiguration : EntityTypeConfiguration<PersonDTO>
{
public override void Configure(EntityTypeBuilder<PersonDTO> builder)
{
builder.HasIndex(person => person.FirstName);
builder.HasIndex(person => person.LastName);
builder.HasIndex(person => person.Email);
base.Configure(builder);
}
}
B-2. Setting up the
DbContext
- represents a session with the database
public class AppDbContext : DbContext
{
public AppDbContext()
{
Database.EnsureCreated();
}
public DbSet<PersonDTO> Persons { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlite(@"data source=Contact.db");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
var types = modelBuilder.Model.GetEntityTypes().Select(t => t.ClrType).ToHashSet();
modelBuilder.ApplyConfigurationsFromAssembly(
Assembly.GetExecutingAssembly(),
t => t.GetInterfaces()
.Any(i => i.IsGenericType
&& i.GetGenericTypeDefinition() == typeof(IEntityTypeConfiguration<>)
&& types.Contains(i.GenericTypeArguments[0]))
);
}
}
NOTES:
* The
constructor
manages the creation of the DB based on the
connection
string in the
OnConfiguring
method. The
OnConfiguring
is also defining that we are using SQLite as our DB system.
*
OnModelCreating
method is using discovery to pull in all of the configuration files - eg:
PersonConfiguration
Part C - Wiring up the Form1
code-behind
public partial class Form1 : Form
{
private AppDbContext dbContext = new();
public Form1()
{
InitializeComponent();
InitData();
}
private void InitData()
{
var dbPersons = dbContext.Set<PersonDTO>();
int count = dbPersons.Count();
if (count == 0)
{
IEnumerable<PersonDTO> persons = LoadData();
dbPersons.AddRange(persons);
dbContext.SaveChanges();
}
dataGridView1.DataSource = dbPersons.ToList();
}
private IEnumerable<PersonDTO> LoadData()
{
string file = Path.Combine(Environment.CurrentDirectory, "MOCK_DATA.json");
string rawJson = File.ReadAllText(file);
return JsonSerializer.Deserialize<IEnumerable<PersonDTO>>(rawJson)!;
}
}
NOTES:
*
InitData
method gets a refernce to the
Persons
table, checks if there are any records. If non, will then load from a JSON file and save to the DB.
*
InitData
will them point the DataGrid to the table and retrieve all Persons.
Here is a link to the project:
WinFormsSqliteEF.zip - Google Drive[
^]
If you want to learn more about Entity Framework Core, here is a great tutorial website:
Entity Framework Tutorial[
^]
Enjoy!