South Africa’s biggest forum. Discuss, discover, and connect with thousands of members.
Pleasure, always happy to chat tech.This is pretty amazing thanks Kosmik
Not quite. This is how I would write your same code
Code:public bool PutCustomer(Customer customer) { using ( var connection = ConectionHelper.GetOpenConnection(databaseConnetionString)) { return connection.Update<Customer>(customer); } }
Connection is a straight SQLConnection, the helper just checks if there is a open one or creates one. The Update is a dapper.contrib.extension that updates the database by using reflection on the object to build its statement.
![]()
DapperLib/Dapper
Dapper - a simple object mapper for .Net. Contribute to DapperLib/Dapper development by creating an account on GitHub.github.com
Makes for very neat repo classes.
Just getting back to this now and started using this contrib library. Next step is to try and incorporate it with Unit of Work pattern. I might not come right but worth a shot. Great library this!
We use mock and nunit as test projects and we do it on a repo and API level.
Done multiqueries yet or combinations of multi and single in same object?
dapper-tutorial.net
dapper-tutorial.net
As you get more complex:
Dapper Multiple - Learn How to Return Multiple Results by Batching
Unlock the power of Dapper Query Multiple to optimize your C# database operations. Learn how to use QueryMultiple and QueryMultipleAsync to return a GridReader and use it to return an anonymous type, strongly type entities, or a scalar value.dapper-tutorial.net
Dapper Multi-Mapping Result - Learn How to Map Result to Many Types
Unlock the power of Dapper by returning a Multi-Mapping Result to map multiple entity types or DTOs in one query. Learn how to query your database and map your navigation by mapping many types.dapper-tutorial.net
Boy I could have used something like this many times in the past. The suffering!!
Thanks Kosmik. Going to put a basic customer/order/items app together and start there.
It's been around for a while, and wasn't limited to C# or Microsoft.Boy I could have used something like this many times in the past. The suffering!!
Just remember Dapper's limit of 7 reflected object outputs per call. Nothing stopping you though from doing multiple calls and building it into a large complex object though, all under the same connection. Just watch your size and data flow.
System.Data.DataException: 'Get<T> only supports an entity with a [Key] or an [ExplicitKey] property'
Not quite. This is how I would write your same code
Code:public bool PutCustomer(Customer customer) { using ( var connection = ConectionHelper.GetOpenConnection(databaseConnetionString)) { return connection.Update<Customer>(customer); } }
Not quite. This is a pure repo class, it's not in the API but a seperate library called by an api. The API and whatever front should be controlling their validation against the model you pass. Your model class should be decorated with the necessary validation attributes to ensure consistent validation whenever it is used. Do you want to allow a call to pass an object in its entirety or have additional rules? You decide whether it can be straight object persists or needs to through additional leg work ( store procedure or foreign constraints).TBH I dont particularly like this implmentation because of the following reasons:
You should be using a domain model to update the customer according to business rules. E.g. client may only update certain customer fields based on permisiions or customer state, etc etc
- I dont like putting db stuff in a api controller (which i assume this is?)
- You are not doing any validation on the customer obj
- There are no business rules applied
- You are updating the db directly from the client’s model of the customer. That is bad practice.
Or maybe this was just illustrative...
Ok got it. Then misunderstood yr post. Then as you say, a concrete repo class abstraction can remove the app’s dependencies on all things dapperNot quite. This is a pure repo class, it's not in the API but a seperate library called by an api. The API and whatever front should be controlling their validation against the model you pass. Your model class should be decorated with the necessary validation attributes to ensure consistent validation whenever it is used. Do you want to allow a call to pass an object in its entirety or have additional rules? You decide whether it can be straight object persists or needs to through additional leg work ( store procedure or foreign constraints).
All dapper is doing, is giving you a shorthand for persistence. Rather than doing a procedure call with multiple parameters to insert/update an object, it uses reflection to build it for you. You still have to apply validation and rules prior to persistence. If there were any rules to be applied, I would have done it earlier in the method before the dapper call.
The examples given to Solarion are just how to use the library.
Ok got it. Then misunderstood yr post. Then as you say, a concrete repo class abstraction can remove the app’s dependencies on all things dapper
Cool i use the same architecture. The domain/model is totally agnostic wrt persistence. I then also run all my business level automated tests against the outward facing services layer. The webapi controller just calls into the services layer. Based on SRP, I believe that the controller responsibllity is purely to be an endpoint for routing a HTTP request and then invoke the services layerYep. And also allow nicely abstracted unit testing on your repo class, keeping test projects with clear separation between the layers.
Personally we build,
Model |
Repo |
---------|
APIs
-------
Service - provides another layer of abstraction between front ends and API.
Web
The first block effectively the data/BL layer even though separated.
I've yet to work on validation. I'm using contosouniversity in that project using the dappercontrib but this error I mentioned earlier has stopped me dead my tracks. I'm funny with the way I work, I will try to get the core functionality working first before continuing especially with something new I'm trying otherwise I'm just wasting time building a house on foundations that are still wet.
For simplicity as per the dapper doc, the following attributes can be used:
Key - maps primary key of table
ExplicitKey - maps a column of a table as a key but not necessarily defined as one in the db
Table - used to specify specific table name if not pluralized of the class name ( default )
Write - True/False to specify if the property is writable or not
Compute - Used to identify computed columns so that they are ignored during persistence.
[Table("Person.Person")]
public class Person
{
[ExplicitKey]
public int BusinessEntityID { get; set; }
public string PersonType { get; set; }
public bool NameStyle { get; set; }
public string Title { get; set; }
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public string Suffix { get; set; }
public int EmailPromotion { get; set; }
public string AdditionalContactInfo { get; set; }
public string Demographics { get; set; }
}