FreeSql Documentation

repository·master·Indexed 24 days ago

https://github.com/dotnetcore/freesql

A high-performance, AOT-compatible ORM for .NET supporting multiple database providers. Features include CodeFirst, DbFirst, Read/Write separation, and optimistic locking. The library provides extensions for BaseEntity CRUD operations, JSON mapping via [JsonMap], a DbContext pattern similar to EFCore, and a generic repository layer with support for table/database sharding and UnitOfWork transaction management.

Tokens
7.7K
Snippets
29
Records
36
Agent score
87%

What's inside FreeSql

  1. Use FreeSql.Provider.Odbc for database access

    master

    FreeSql.Provider.Odbc provides ODBC access to various databases. It includes specialized implementations for SqlServer, PostgreSQL, Oracle, MySql, Dameng (达梦), Kingbase (人大金仓), and a generic implementation.

    Warning: ODBC is considered a legacy technology with inconsistent standards across database vendors. It is recommended to use native providers (like FreeSql.Provider.SqlServer) instead of ODBC whenever possible.

    Compared to native ADO.NET providers, the ODBC provider supports fewer basic types, though it retains most other features including CodeFirst automatic migrations.

  2. Define and Initialize FreeSql for Repository Use

    master

    Before using repositories, you must initialize IFreeSql as a Singleton. Ensure you use UseAutoSyncStructure(true) if you want the database schema to automatically migrate to match your entities.

    static IFreeSql fsql = new FreeSql.FreeSqlBuilder()
        .UseConnectionString(FreeSql.DataType.Sqlite, @"Data Source=|DataDirectory|\document.db;Pooling=true;Max Pool Size=10")
        .UseAutoSyncStructure(true)
        .Build();
    
    public class Song {
        [Column(IsIdentity = true)]
        public int Id { get; set; }
        public string Title { get; set; }
    }
    static IFreeSql fsql = new FreeSql.FreeSqlBuilder()
        .UseConnectionString(FreeSql.DataType.Sqlite, @"Data Source=|DataDirectory|\document.db;Pooling=true;Max Pool Size=10")
        .UseAutoSyncStructure(true) //自动迁移实体的结构到数据库
        .Build(); //请务必定义成 Singleton 单例模式
    
    public class Song {
        [Column(IsIdentity = true)]
        public int Id { get; set; }
        public string Title { get; set; }
    }
  3. Install FreeSql.Extensions.BaseEntity

    master

    To use the BaseEntity extension, you need to install the BaseEntity package and a database provider (e.g., Sqlite).

    dotnet add package FreeSql.Extensions.BaseEntity
    
    dotnet add package FreeSql.Provider.Sqlite
  4. Use FreeSql.DbContext via OnConfiguring

    master

    You can implement a DbContext by overriding the OnConfiguring method and linking it to your IFreeSql instance using builder.UseFreeSql(). Note that DbContext objects are not thread-safe.

    public class SongContext : DbContext {
        public DbSet<Song> Songs { get; set; }
        public DbSet<Tag> Tags { get; set; }
    
        protected override void OnConfiguring(DbContextOptionsBuilder builder) {
            builder.UseFreeSql(fsqlInstance);
        }
    }
  5. Initialize FreeSql with CodeFirst and AutoSync

    master
    Use FreeSqlBuilder to configure your connection string and database settings. It is highly recommended to define the IFreeSql instance as a Singleton. Setting UseAutoSyncStructure(true) enables automatic synchronization of entity structures to the database (CodeFirst mode).
  6. Use UnitOfWork for Transaction Management

    master

    UnitOfWork allows you to manage multiple repositories within a single transaction. Use uow.Commit() to execute all operations.

    To use UnitOfWork with Dependency Injection in ASP.NET Core, you should implement a UnitOfWorkRepository that accepts IUnitOfWork in its constructor and register it as Scoped.

    using (var uow = fsql.CreateUnitOfWork()) {
        var songRepo = uow.GetRepository<Song>();
        var userRepo = uow.GetRepository<User>();
    
        // Perform repository operations here
        
        uow.Commit();
    }
  7. Manage Transactions with BaseEntity

    master

    Because AsyncLocal compatibility varies, transactions for BaseEntity must be managed externally. You provide a function to BaseEntity.Initialization that retrieves the current IUnitOfWork from an AsyncLocal storage.

    Implementation Steps

    1. Define a static AsyncLocal<IUnitOfWork>.
    2. Initialize BaseEntity with a callback returning that value.
    3. Wrap your operations in a using block with fsql.CreateUnitOfWork() and manage the AsyncLocal value within the scope.
    static AsyncLocal<IUnitOfWork> _asyncUow = new AsyncLocal<IUnitOfWork>();
    
    // Initialize with the provider callback
    BaseEntity.Initialization(fsql, () => _asyncUow.Value);
    
    // Usage in a scoped operation
    using (var uow = fsql.CreateUnitOfWork())
    {
        _asyncUow.Value = uow;
    
        try
        {
            // BaseEntity internal CRUD methods will now use this transaction
        }
        finally
        {
            _asyncUow.Value = null;
        }
        
        uow.Commit();
    }
  8. Define entities using BaseEntity

    master

    BaseEntity provides a CodeFirst approach that automatically handles common fields like CreateTime, UpdateTime, and soft delete logic.

    • Integer/Long Primary Keys: If you specify int or long as the second generic parameter, the Id is treated as an auto-incrementing identity.
    • Guid Primary Keys: If you specify Guid, the extension automatically generates ordered, unique Guid values during insertion.
    • Customizing Identity: To disable auto-increment for integer keys, override the Id property and use the [Column(IsIdentity = false)] attribute.
    // Integer auto-incrementing primary key
    public class UserGroup : BaseEntity<UserGroup, int>
    {
        public string GroupName { get; set; }
    }
    
    // Disabling auto-increment for integer primary key
    public class UserGroup : BaseEntity<UserGroup, int>
    {
        [Column(IsIdentity = false)]
        public override int Id { get; set; }
        public string GroupName { get; set; }
    }
    
    // Guid primary key (automatically generates ordered Guids)
    public class User : BaseEntity<User, Guid>
    {
        public string UserName { get; set; }
    }
  9. Initialize FreeSql with SQLite

    master

    Use FreeSqlBuilder to configure your connection string and database settings. It is recommended to define the IFreeSql instance as a singleton. You can use .UseAutoSyncStructure(true) to automatically synchronize your entity structures with the database (CodeFirst).

    static IFreeSql fsql = new FreeSql.FreeSqlBuilder()
      .UseConnectionString(FreeSql.DataType.Sqlite, @"Data Source=document.db")
      .UseAutoSyncStructure(true) //automatically synchronize the entity structure to the database
      .Build(); //be sure to define as singleton mode
  10. Use FreeSql Repositories

    master

    You can access repositories in three ways:

    1. Extension Method: Use fsql.GetRepository<T>(). Note that Repository objects are not thread-safe.
    2. Inheritance: Create a custom repository by inheriting from BaseRepository<TEntity, TKey>.
    3. Dependency Injection: Register repositories in your service collection using AddFreeRepository to enable global filtering (e.g., for multi-tenancy or soft deletes).

    Warning: Repository objects are not thread-safe.

    // 1. IFreeSql extension method
    var curd = fsql.GetRepository<Song>();
    
    // 2. Inheritance implementation
    public class SongRepository : BaseRepository<Song, int> {
        public SongRepository(IFreeSql fsql) : base(fsql, null, null) {}
    }
    
    // 3. Dependency Injection
    public void ConfigureServices(IServiceCollection services) {
        services.AddSingleton<IFreeSql>(Fsql);
        services.AddFreeRepository(filter => filter
            .Apply<ISoftDelete>("SoftDelete", a => a.IsDeleted == false)
            .Apply<ITenant>("Tenant", a => a.TenantId == 1)
            ,
            this.GetType().Assembly
        );
    }
    
    // Usage in Controller
    public SongsController(GuidRepository<Song> repos1) {
    }