3 Effective Ways to Use the Dapper Plus Context

The DapperPlusContext is the class where all the magic happens. All Bulk Extension and Single Extension methods execute use an instance of a DapperPlusContext. Even when you utilize methods through a connection or transaction, you are employing what we call the global context, which is simply a new instance of the DapperPlusContext stored in a static variable in the DapperPlusManager:

public class DapperPlusManager
{
    public static DapperPlusContext DefaultContext { get; set; } = new DapperPlusContext();
    
    // ...code...
}

But what exactly is a DapperPlusContext?

To put it simply, a DapperPlusContext is a class that contains all your mapping and options information, which will be utilized whenever you call a method from it.

There are three different ways to use the DapperPlusContext:

  • Global Context
  • Instance Context
  • Inheritance Context

Each method has its pros and cons; choosing the right one will depend on your specific needs.

Global Context

The global context mapping is the most commonly used one. This mapping is applied whenever you execute an action from the connection or transaction.

However, there is one simple rule to follow: This is global, so ensure wherever you map, it's called only once.

A common mistake people make is performing a mapping for the global context inside a method. This can lead to potential concurrency issues, as one call of the method might be at the step of re-creating the mapping while another call might be using the mapping.

As we noted in our introduction, the global context mapping is simply an instance of the DapperPlusContext stored in a variable in the DapperPlusManager:

public class DapperPlusManager
{
    public static DapperPlusContext DefaultContext { get; set; } = new DapperPlusContext();
    
    // ...code...
}

You can configure mapping and options directly through the DapperPlusManager or DefaultContext:

// commonly used method
DapperPlusManager.Entity<Product>().Identity(x => x.ProductID);

// alternative method using DefaultContext
DapperPlusManager.DefaultContext.Entity<Product>().Identity(x => x.ProductID);

Instance Context

The instance mapping allows you to map your entities specifically for the scope of a DapperPlusContext instance. You then call Bulk Extension Methods directly from this instance.

This approach is particularly useful inside a method when the context of the mapping might change depending on certain parameters. In the following example, you will see that we've added a parameter to specify whether our mapping should keep the identity value provided and the column names to insert:

public static void CustomInsert(IEnumerable<Product> products, bool keepIdentityValue, List<string> mappingColumnNames)
{
	var connection = new SqlConnection(FiddleHelper.GetConnectionStringSqlServer());
	var context = new DapperPlusContext(connection);

	var mapping = context.Entity<Product>().Identity(x => x.ProductID);
	
	mappingColumnNames.ForEach(x => mapping.Map(x));

	if(keepIdentityValue)
	{
		mapping.UseBulkOptions(options => options.InsertKeepIdentity = true);
	}

	context.BulkInsert(products);
}

Online Example

The instance context is the most flexible way to use our library, especially when you cannot determine the mapping and options in advance.

Inheritance Context

Inheritance mapping allows you to define how entities are mapped within the scope of a context instance that inherits from DapperPlusContext. This method is particularly useful when you need different mappings based on parameters passed in your constructors, or when you wish to maintain these mappings in your own variable.

Here's an example where a specialized ProductContext is set up to handle only products:

public class ProductContext : DapperPlusContext
{
    public ProductContext() : base(new SqlConnection(FiddleHelper.GetConnectionStringSqlServer()))
    {
        this.Entity<Product>().Identity(x => x.ProductID, true);
    }
}

var productContext = new ProductContext();
productContext.BulkInsert(products);

Online Example

This inheritance context approach allows for robust, context-specific configurations that are encapsulated within their own classes, thereby enhancing modularity and readability of your data access layer.

Conclusion

In this article, we explored three different ways to use the Dapper Plus context.

It's important not to limit yourself to only the global context mapping, as it does not cover all scenarios.

Typically, people new to our library start by using the global context, but they often encounter scenarios where using an instance context or an inheritance context might be a more suitable solution for their specific needs.


Last updated: 2024-09-25
Author:


Contents