ORM Frameworks

December 12, 2025 ยท View on GitHub

Sharp-ABP provides integration with multiple ORM frameworks, giving you flexibility in data access strategies.

FreeSql

FreeSql ORM framework integration with support for multiple database providers.

Installation

Install the core package and your database provider:

# Core FreeSql package
dotnet add package SharpAbp.Abp.FreeSql

# Database-specific packages
dotnet add package SharpAbp.Abp.FreeSql.MySQL
dotnet add package SharpAbp.Abp.FreeSql.PostgreSql
dotnet add package SharpAbp.Abp.FreeSql.SqlServer
dotnet add package SharpAbp.Abp.FreeSql.Oracle
dotnet add package SharpAbp.Abp.FreeSql.Sqlite
dotnet add package SharpAbp.Abp.FreeSql.DM        # DaMeng Database

Configuration

Configure in appsettings.json:

{
  "ConnectionStrings": {
    "Default": "Server=localhost;Database=MyDb;User Id=sa;Password=****;"
  },
  "FreeSql": {
    "DataType": "SqlServer",
    "ConnectionString": "Server=localhost;Database=MyDb;User Id=sa;Password=****;",
    "AutoSyncStructure": false,
    "LazyLoading": false
  }
}

Add the module dependency:

[DependsOn(
    typeof(AbpFreeSqlModule),
    typeof(AbpFreeSqlSqlServerModule)  // Or your database provider
)]
public class YourModule : AbpModule
{
    public override void ConfigureServices(ServiceConfigurationContext context)
    {
        var configuration = context.Services.GetConfiguration();

        Configure<AbpFreeSqlOptions>(options =>
        {
            options.PreConfigure = freeSql =>
            {
                freeSql.GlobalFilter
                    .Apply<ISoftDelete>("SoftDelete", a => a.IsDeleted == false);
            };

            options.ConfigureFreeSql = (sp, freeSql) =>
            {
                // Additional configuration
                freeSql.Aop.CurdBefore += (s, e) =>
                {
                    // Log SQL
                    Console.WriteLine($"SQL: {e.Sql}");
                };
            };
        });
    }
}

Usage Example

Basic CRUD Operations

public class ProductRepository : ITransientDependency
{
    private readonly IFreeSql _freeSql;

    public ProductRepository(IFreeSql freeSql)
    {
        _freeSql = freeSql;
    }

    // Query
    public async Task<List<Product>> GetAllProductsAsync()
    {
        return await _freeSql.Select<Product>()
            .Where(x => x.IsActive)
            .OrderBy(x => x.Name)
            .ToListAsync();
    }

    // Query with pagination
    public async Task<PagedResult<Product>> GetPagedAsync(int page, int pageSize)
    {
        var query = _freeSql.Select<Product>()
            .Where(x => x.IsActive);

        var total = await query.CountAsync();
        var items = await query
            .Page(page, pageSize)
            .ToListAsync();

        return new PagedResult<Product>
        {
            Items = items,
            Total = total
        };
    }

    // Insert
    public async Task<Product> CreateAsync(Product product)
    {
        await _freeSql.Insert(product).ExecuteAffrowsAsync();
        return product;
    }

    // Update
    public async Task<Product> UpdateAsync(Product product)
    {
        await _freeSql.Update<Product>()
            .SetSource(product)
            .ExecuteAffrowsAsync();
        return product;
    }

    // Delete
    public async Task DeleteAsync(Guid id)
    {
        await _freeSql.Delete<Product>()
            .Where(x => x.Id == id)
            .ExecuteAffrowsAsync();
    }
}

Advanced Queries

public class AdvancedQueryExample
{
    private readonly IFreeSql _freeSql;

    public AdvancedQueryExample(IFreeSql freeSql)
    {
        _freeSql = freeSql;
    }

    // Join query
    public async Task<List<OrderWithCustomer>> GetOrdersWithCustomersAsync()
    {
        return await _freeSql.Select<Order, Customer>()
            .LeftJoin((o, c) => o.CustomerId == c.Id)
            .ToListAsync((o, c) => new OrderWithCustomer
            {
                OrderId = o.Id,
                OrderNumber = o.OrderNumber,
                CustomerName = c.Name
            });
    }

    // Aggregate query
    public async Task<decimal> GetTotalSalesAsync()
    {
        return await _freeSql.Select<Order>()
            .Where(x => x.Status == OrderStatus.Completed)
            .SumAsync(x => x.TotalAmount);
    }

    // Group by
    public async Task<List<CategorySales>> GetSalesByCategoryAsync()
    {
        return await _freeSql.Select<Product, OrderItem>()
            .InnerJoin((p, oi) => p.Id == oi.ProductId)
            .GroupBy((p, oi) => p.CategoryId)
            .ToListAsync(g => new CategorySales
            {
                CategoryId = g.Key,
                TotalQuantity = g.Sum((p, oi) => oi.Quantity),
                TotalAmount = g.Sum((p, oi) => oi.Amount)
            });
    }
}

Dapper

Dapper micro-ORM framework integration for lightweight data access.

Installation

dotnet add package SharpAbp.Abp.Dapper

Configuration

Add the module dependency:

[DependsOn(typeof(AbpDapperModule))]
public class YourModule : AbpModule
{
    public override void ConfigureServices(ServiceConfigurationContext context)
    {
        // Dapper is ready to use with ABP's connection strings
    }
}

Usage Example

Basic Queries

public class ProductRepository : DapperRepository<YourDbContext>, ITransientDependency
{
    public ProductRepository(IDbContextProvider<YourDbContext> dbContextProvider)
        : base(dbContextProvider)
    {
    }

    public async Task<List<Product>> GetActiveProductsAsync()
    {
        var dbConnection = await GetDbConnectionAsync();
        var sql = "SELECT * FROM Products WHERE IsActive = @IsActive";

        return (await dbConnection.QueryAsync<Product>(sql, new { IsActive = true }))
            .ToList();
    }

    public async Task<Product> GetByIdAsync(Guid id)
    {
        var dbConnection = await GetDbConnectionAsync();
        var sql = "SELECT * FROM Products WHERE Id = @Id";

        return await dbConnection.QueryFirstOrDefaultAsync<Product>(sql, new { Id = id });
    }

    public async Task<int> CreateAsync(Product product)
    {
        var dbConnection = await GetDbConnectionAsync();
        var sql = @"INSERT INTO Products (Id, Name, Price, IsActive, CreationTime)
                    VALUES (@Id, @Name, @Price, @IsActive, @CreationTime)";

        return await dbConnection.ExecuteAsync(sql, product);
    }

    public async Task<int> UpdateAsync(Product product)
    {
        var dbConnection = await GetDbConnectionAsync();
        var sql = @"UPDATE Products
                    SET Name = @Name, Price = @Price, IsActive = @IsActive
                    WHERE Id = @Id";

        return await dbConnection.ExecuteAsync(sql, product);
    }
}

Advanced Queries with Multiple Result Sets

public class OrderRepository : DapperRepository<YourDbContext>
{
    public OrderRepository(IDbContextProvider<YourDbContext> dbContextProvider)
        : base(dbContextProvider)
    {
    }

    public async Task<OrderWithDetails> GetOrderWithDetailsAsync(Guid orderId)
    {
        var dbConnection = await GetDbConnectionAsync();
        var sql = @"
            SELECT * FROM Orders WHERE Id = @OrderId;
            SELECT * FROM OrderItems WHERE OrderId = @OrderId;
            SELECT * FROM Customers c
            INNER JOIN Orders o ON c.Id = o.CustomerId
            WHERE o.Id = @OrderId";

        using (var multi = await dbConnection.QueryMultipleAsync(sql, new { OrderId = orderId }))
        {
            var order = await multi.ReadFirstOrDefaultAsync<Order>();
            var orderItems = (await multi.ReadAsync<OrderItem>()).ToList();
            var customer = await multi.ReadFirstOrDefaultAsync<Customer>();

            return new OrderWithDetails
            {
                Order = order,
                OrderItems = orderItems,
                Customer = customer
            };
        }
    }

    public async Task<List<T>> QueryAsync<T>(string sql, object parameters = null)
    {
        var dbConnection = await GetDbConnectionAsync();
        return (await dbConnection.QueryAsync<T>(sql, parameters)).ToList();
    }
}

EntityFrameworkCore

Entity Framework Core integration with support for DM (DaMeng) and GaussDB.

Installation

# Core package
dotnet add package SharpAbp.Abp.EntityFrameworkCore

# Database-specific packages
dotnet add package SharpAbp.Abp.EntityFrameworkCore.DM       # DaMeng
dotnet add package SharpAbp.Abp.EntityFrameworkCore.GaussDB  # GaussDB

Configuration

For DaMeng Database

[DependsOn(
    typeof(AbpEntityFrameworkCoreModule),
    typeof(AbpEntityFrameworkCoreDmModule)
)]
public class YourEntityFrameworkCoreModule : AbpModule
{
    public override void ConfigureServices(ServiceConfigurationContext context)
    {
        context.Services.AddAbpDbContext<YourDbContext>(options =>
        {
            options.AddDefaultRepositories(includeAllEntities: true);
        });

        Configure<AbpDbContextOptions>(options =>
        {
            options.UseDm();
        });
    }
}

Configure connection string in appsettings.json:

{
  "ConnectionStrings": {
    "Default": "Server=localhost;Port=5236;User Id=SYSDBA;PWD=SYSDBA;Database=MyDb;"
  }
}

For GaussDB

[DependsOn(
    typeof(AbpEntityFrameworkCoreModule),
    typeof(AbpEntityFrameworkCoreGaussDBModule)
)]
public class YourEntityFrameworkCoreModule : AbpModule
{
    public override void ConfigureServices(ServiceConfigurationContext context)
    {
        context.Services.AddAbpDbContext<YourDbContext>(options =>
        {
            options.AddDefaultRepositories(includeAllEntities: true);
        });

        Configure<AbpDbContextOptions>(options =>
        {
            options.UseGaussDB();
        });
    }
}

Configure connection string in appsettings.json:

{
  "ConnectionStrings": {
    "Default": "Host=localhost;Port=5432;Database=MyDb;Username=user;Password=****;"
  }
}

Usage Example

Define DbContext

public class YourDbContext : AbpDbContext<YourDbContext>
{
    public DbSet<Product> Products { get; set; }
    public DbSet<Order> Orders { get; set; }
    public DbSet<Customer> Customers { get; set; }

    public YourDbContext(DbContextOptions<YourDbContext> options)
        : base(options)
    {
    }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);

        builder.Entity<Product>(b =>
        {
            b.ToTable("Products");
            b.ConfigureByConvention();

            b.Property(x => x.Name).IsRequired().HasMaxLength(128);
            b.Property(x => x.Price).HasColumnType("decimal(18,2)");

            b.HasIndex(x => x.Name);
        });

        builder.Entity<Order>(b =>
        {
            b.ToTable("Orders");
            b.ConfigureByConvention();

            b.HasOne(x => x.Customer)
                .WithMany()
                .HasForeignKey(x => x.CustomerId);

            b.HasMany(x => x.OrderItems)
                .WithOne()
                .HasForeignKey(x => x.OrderId);
        });
    }
}

Repository Usage

public class ProductAppService : ApplicationService
{
    private readonly IRepository<Product, Guid> _productRepository;

    public ProductAppService(IRepository<Product, Guid> productRepository)
    {
        _productRepository = productRepository;
    }

    public async Task<List<ProductDto>> GetListAsync()
    {
        var products = await _productRepository.GetListAsync();
        return ObjectMapper.Map<List<Product>, List<ProductDto>>(products);
    }

    public async Task<ProductDto> GetAsync(Guid id)
    {
        var product = await _productRepository.GetAsync(id);
        return ObjectMapper.Map<Product, ProductDto>(product);
    }

    public async Task<ProductDto> CreateAsync(CreateProductDto input)
    {
        var product = new Product
        {
            Name = input.Name,
            Price = input.Price,
            IsActive = true
        };

        await _productRepository.InsertAsync(product);
        return ObjectMapper.Map<Product, ProductDto>(product);
    }

    public async Task UpdateAsync(Guid id, UpdateProductDto input)
    {
        var product = await _productRepository.GetAsync(id);

        product.Name = input.Name;
        product.Price = input.Price;

        await _productRepository.UpdateAsync(product);
    }

    public async Task DeleteAsync(Guid id)
    {
        await _productRepository.DeleteAsync(id);
    }
}

Advanced EF Core Queries

public class AdvancedOrderService : ApplicationService
{
    private readonly IRepository<Order, Guid> _orderRepository;

    public AdvancedOrderService(IRepository<Order, Guid> orderRepository)
    {
        _orderRepository = orderRepository;
    }

    public async Task<List<OrderDto>> GetOrdersWithCustomerAsync()
    {
        var query = await _orderRepository.WithDetailsAsync(x => x.Customer, x => x.OrderItems);

        var orders = await AsyncExecuter.ToListAsync(
            query.Where(x => x.Status == OrderStatus.Pending)
                .OrderByDescending(x => x.CreationTime)
        );

        return ObjectMapper.Map<List<Order>, List<OrderDto>>(orders);
    }

    public async Task<decimal> GetTotalRevenueAsync()
    {
        var queryable = await _orderRepository.GetQueryableAsync();

        return await AsyncExecuter.SumAsync(
            queryable.Where(x => x.Status == OrderStatus.Completed),
            x => x.TotalAmount
        );
    }
}