Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(Third-party library) Harbin.DataAccess - Generic Repository Pattern using Dapper, Dapper FastCRUD and DapperQueryBuilder #152

Closed
Drizin opened this issue Dec 7, 2020 · 2 comments

Comments

@Drizin
Copy link

Drizin commented Dec 7, 2020

Harbin.DataAccess implements Generic Repositories (Generic Repository Pattern) using "raw" Dapper, Dapper.FastCRUD, and DapperQueryBuilder.

  • The Inserts/Updates/Deletes are automatically generated by Dapper FastCRUD (class should be decorated with attributes for keys/autoincrement columns)
  • Supports FastCRUD bulk update, bulk delete, and async methods.
  • Repositories can be extended with custom Queries and custom Commands (allows/promotes CQRS separation)
  • Queries can be defined manually (raw sql) or using Dapper FastCRUD syntax
  • Dynamic Queries (dynamic number of conditions) can be built using DapperQueryBuilder
  • There are Read-only Connection Wrappers and Read-only Repositories, so it's easy to use read-replicas (or multiple databases)
  • Support for ADO.NET transactions
  • Support for mocking Queries and Commands

Sample Insert/Update/Delete (Generic Repository - this uses Dapper FastCRUD):

var conn = new ReadWriteDbConnection(new System.Data.SqlClient.SqlConnection(connectionString));

// Get a IReadWriteRepository<TEntity> which offers some helpers to Query and Write our table:
var repo = conn.GetReadWriteRepository<ContactType>();

var contactType = repo.QueryAll().First();

// Updating a record
contactType.ModifiedDate = DateTime.Now;
repo.Update(contactType);

// Adding a new record
var newContactType = new ContactType() { Name = "NewType", ModifiedDate = DateTime.Now };
repo.Insert(newContactType);
// FastCRUD will automatically update the auto-generated columns back (identity or guid)

// Deleting a record
repo.Delete(newContactType);
[Table("ContactType", Schema = "Person")]
public class ContactType
{
    [Key] // if column is part of primary key
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)] // if column is auto-increment
    public int ContactTypeId { get; set; }

    public DateTime ModifiedDate { get; set; }

    public string Name { get; set; }
}

Sample Dynamic Queries:

var conn = new ReadDbConnection(new System.Data.SqlClient.SqlConnection(connectionString));


// Get a IReadRepository<TEntity> which offers some helpers to Query our table:
var repo = conn.GetReadRepository<Person>();

// Custom Query (pure Dapper)
var people = repo.Query("SELECT * FROM Person.Person WHERE PersonType = @personType ", new { personType = "EM" } );

// DapperQueryBuilder allows to dynamically append conditions using string interpolation (but injection-safe)

string type = "EM"; string search = "%Sales%";

var dynamicQuery = repo.QueryBuilder(); // if not specified query is initialized with "SELECT * FROM tablename"
dynamicQuery.Where($"PersonType = {type}");
dynamicQuery.Where($"ModifiedDate >= {DateTime.Now.AddDays(-1)} ");
dynamicQuery.Where($"Name LIKE {search}");

// Result is SELECT * FROM [Person].[Person] WHERE PersonType = @p0 AND ModifiedDate >= @p1 AND Name LIKE @p2
var people = dynamicQuery.Query();

Extending Repositories (adding custom Queries and Commands) using Inheritance:

public class PersonRepository : ReadWriteDbRepository<Person>
{
  public PersonRepository(IReadWriteDbConnection db) : base(db)
  {
  }
  public virtual IEnumerable<Person> QueryRecentEmployees()
  {
    return this.Query("SELECT TOP 10 * FROM [Person].[Person] WHERE [PersonType]='EM' ORDER BY [ModifiedDate] DESC");
  }
  public virtual void UpdateCustomers()
  {
    this.Execute("UPDATE [Person].[Person] SET [FirstName]='Rick' WHERE [PersonType]='EM' ");
  }
}

public void Sample()
{
  // Registers that GetReadWriteRepository<Person>() should return a derived type PersonRepository
  ReadWriteDbConnection.RegisterRepositoryType<Person, PersonRepository>();

  var conn = new ReadWriteDbConnection(new System.Data.SqlClient.SqlConnection(connectionString));  
  
  // we know exactly what subtype to expect, so we can just cast.
  var repo = (PersonRepository) conn.GetReadWriteRepository<Person>();
  
  repo.UpdateCustomers();
  var recentEmployees = repo.QueryRecentEmployees();
}

Full documentation here.

There are also sample scripts which extract the schema of an existing SQL Server database and generate POCO classes (with attributes [Key], [DatabaseGenerated(DatabaseGeneratedOption.Identity)], etc.) based on the schema.

@denniscpolley
Copy link

This is what I have been searching for, THANK YOU! How would you use your api with a UOW pattern?

@Drizin
Copy link
Author

Drizin commented Dec 10, 2020

Hi @denniscpolley , I'm glad you liked. Would you mind asking this question in Harbin issues? I'd like to keep the technical discussion there, so it can benefit other users. Thanks!

Repository owner locked and limited conversation to collaborators Mar 3, 2022
@MoonStorm MoonStorm converted this issue into discussion #161 Mar 3, 2022

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants