I’m developing a C# WPF desktop application where I need to read/write to an SQL database (SQL server) regularly. Now I want to map the data from the database to objects in C#. I can’t use Entity Framework so I’m doing all my data access through Dapper and stored procedures.
As an example, I have modeled this sample database
The C# objects would look similar to this.
public class Manager {
   public string Name { get; set; }
   public string Phone { get; set; }
   public List<Facility> Facilities {get; set;}
} 
public class City {
   public string Name { get; set; }
   public string Description{ get; set; }
   public List<Facility> Facilities {get; set;}
} 
public class Facility {
   public string Name { get; set; }
   public string Description{ get; set; }
} 
I have tried to map the data with slapper automapper but it didn’t work. Can I use Dapper to map all these ? Do i even need to map every Table to a class in C# with its relationships ? Or could I just write a stored procedure that returns all the entries already matched and create one big class with all the data as properties ?
Advertisement
Answer
You can use Dapper to make it work and you have several options:
First option
You can query parent entity and then query all child entities. The code will look like this:
var manager = await connection.QueryFirstOrDefaultAsync<Manager>("SELECT * FROM Manager AS m WHERE m.Name = @name", new {name = name}); // use your query and your parameters
manager.Facilities = await connection.QueryAsync<Manager>("SELECT * FROM Facilities AS f WHERE f.ManagerId = @managerId", new {managerId = manager.ManagerId}); 
// use similar queries to get Cities
Second option
You can use multimapping to get multiple entities (but you should know, that it allows to query up to 7 dependent entities – for your case it will be enough):
public async Task<IEnumerable<Manager>> GetManagerWithFacilitiesByManagerName(string name)
{
    var managersDictionary = new Dictionary<int, Manager>();
    await connection.Query<Manager, Facility, Manager>(
       @"SELECT * 
         FROM Manager AS m 
         INNER JOIN Facilities as f ON f.ManagerId = m.ManagerId
         WHERE m.Name = @name", 
       (manager, facility) => 
       { 
           Manager managerEntity;
           if (managersDictionary.ContainsKey(manager.ManagerId)
           {
               managerEntity = managersDictionary[manager.ManagerId];
           } 
           else 
           {
               managerEntity = manager;
               managerEntity.Facilities = new List<Facilities>();
               managersDictionary.Add(managerEntity.ManagerId, managerEntity);
           }
           managerEntity.Facilities.Add(facility);
           return managerEntity;
       }
       new {name = name},
       splitOn: "ManagerId,FacilityId") // properties where to split entity
    return managersDictionary.Values;    
} 
If you want only first Manager just use managersDictionary.Values.FirstOrDefault() and change return type to Task<Manager>.
