Please rate my web service

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.


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!
 
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?
 
Just maybe a design point, we use an additional model for more complex models. Let's say ClassroomModel is a complex model, it will have the simple model Classroom, a couple of properties that help utilize it and maybe a List of Students enrolled or something else as well. That level of detail is only necessary if I'm doing major display work on the model, otherwise the lighter "pure" model should be used to keep overhead down on data retrieval and transmissions.
 
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?

No that is what I am about to work on so will need to just put a basic project together first and take it from there.
 
As you get more complex:

 
As you get more complex:


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.
 
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.

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.
 
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.

I put something together over the weekend using ContosoUniveristy database. It's not using any multiqueries or anything at this point but I am trying to get a genericRepo/UnitofWork going with DapperContrib.Extensions.

Not sure this will even work but I got a bit carried away and will see where it goes. The issue is using a generic repository with dapper which may or may not be a good idea. It's worth a shot.


I put the brakes on after getting this:

System.Data.DataException: 'Get<T> only supports an entity with a [Key] or an [ExplicitKey] property'

I know why it's doing it, I just don't know how to fix it. A few Stackoverflow shows a few guys actually abandoned dappercontrib altogether because of this. Anyway onward and forward. I think this could be a decent project.
 
Last edited:
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);
    }
}

TBH I dont particularly like this implmentation because of the following reasons:
  • 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.
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

Or maybe this was just illustrative...
 
TBH I dont particularly like this implmentation because of the following reasons:
  • 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.
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

Or maybe this was just illustrative...
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).

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.
 
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).

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
 
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

Yep. 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.
 
Yep. 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.
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 layer
 
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.
 
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.

I only read your error now, all that's missing is the [Key] attribute on your primary key property of your model. For example:

public class Student ()
{
[Key]
public int StudentID { get;set; }

public DateTime DOB { get; set; }

......

}

The get extension uses reflection to obtain the primary key without declaration in the call but you need to specify the key via an attribute in your model. We only use that if its a simplistic retreival ie: via a primary key, otherwise we use the .Query<T> extension and passed parameters.
 
Last edited:
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.
 
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.

Alright I ditched contoso and any other database I was trying and headed straight for AdventureWorks. Was getting the same issue.

I tried key and explicitkey to no avail however what did fix it was having to use a fully qualifying table name as they are shown in AdventureWorks. Why Microsoft did this database that way is a mystery to me :X3:

Edit: I've updated Github. Nowhere near finished but at least getting some joy.

C#:
[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; }
    }

adventure-Works.jpg


For other databases it would likely be dbo.Person
 
Top
Sign up to the MyBroadband newsletter
X