4

I need to map a one to many flattened SQL query into nested objects using Dapper.net.

Slapper.Automapper seems a good way of doing this; as detailed in the answer to this question:

How do I write one to many query in Dapper.Net?

Erroneous dataset I get using Guids: enter image description here

public string MrFlibble3()
{
    using (var connection = new SqlConnection(Constr))
    {
        Slapper.AutoMapper.Cache.ClearInstanceCache();

        const string sql = @"SELECT tc.[IDG] as ContactIdg
                                ,tc.[ContactName] as ContactName
                                ,tp.[Idg] AS TestPhones_PhoneIdg
                                ,tp.[ContactIdg] AS TestPhones_ContactIdg
                                ,tp.[Number] AS TestPhones_Number
                                FROM TestContact tc
                                INNER JOIN TestPhone tp ON tc.Idg = tp.ContactIdg";

        // Step 1: Use Dapper to return the  flat result as a Dynamic.
        dynamic test = connection.Query<dynamic>(sql);

        // Step 2: Use Slapper.Automapper for mapping to the POCO Entities.
        // - IMPORTANT: Let Slapper.Automapper know how to do the mapping;
        //   let it know the primary key for each POCO.
        // - Must also use underscore notation ("_") to name parameters;
        //   see Slapper.Automapper docs.
        Slapper.AutoMapper.Configuration.AddIdentifiers(typeof(TestContact), new List<string> { "ContactIDg" });
        Slapper.AutoMapper.Configuration.AddIdentifiers(typeof(TestPhone), new List<string> { "PhoneIdg" });

        var testContact = (Slapper.AutoMapper.MapDynamic<TestContact>(test) as IEnumerable<TestContact>).ToList();

        string flibblethis = "";

        foreach (var c in testContact)
        {
            foreach (var p in c.TestPhones)
            {
                // Console.Write("ContactName: {0}: Phone: {1}\n", c.ContactName, p.Number);
                flibblethis += "Contact Name: " + c.ContactName + ". Number: " + p.Number + "<br />";
            }
        }

        return flibblethis;
    }
}

It works well in the example - except Slapper.Automapper doesn't appear to work if Ids are Guids rather than ints.

Is there any way to use Guid IDs with Slapper.Automapper - or is there an alternative way to map this using Dapper.net?

(Slapper.Automapper isn't widely used and I can't see anything online about this issue).

Community
  • 1
  • 1
niico
  • 11,206
  • 23
  • 78
  • 161
  • Flattening in the query only to rehydrate into nested objects puzzles me a bit. Why would you want to do this? If it's worth putting columns together in a result set, it's worth keeping them together in a POCO, no? – bbsimonbb Oct 12 '16 at 07:20
  • OK How can I do that? – niico Oct 12 '16 at 12:39
  • My thinking was flattening = 1 query. I would like to do this without hitting the database once for every related object - something Slapper does well with ID keyed tables. – niico Oct 12 '16 at 13:55
  • I'm not convinced. The cost in complexity, processing, more data on the wire, will likely outweigh any advantage from using just 1 query. I see some micro ORMs do this, Dapper, and PetaPoco. I'm the author of a tool in this space, [QueryFirst](https://visualstudiogallery.msdn.microsoft.com/eaf390af-afc1-4994-a442-ec95923dafcb), (that might be useful to you. It deals with Guids) I wonder if I should incorporate this feature. But then I think a sql query returns a rowset. The POCO you want is one that encapsulates a row of results. If you don't like the rowset, change the query. Keep it simple. – bbsimonbb Oct 12 '16 at 21:41
  • Thanks. Let's step back - I am just looking for a way to fill a collection of objects - and these objects in the collection themselves have a collection of objects. I just need an efficient way of doing this. Open to suggestions. I would rather not hit the database 20 times just to display 1 user facing page, that just seems like a very bad idea. I guess I could grab the result set in one round trip and 'manually' hydrate the objects - but that's cumbersome and I guess slow. – niico Oct 12 '16 at 23:14
  • :-) you may be looking for the convenience of EF, without EF. What's cumbersome to write is not necessarily slow to run. If you're using Dapper, it's because you want to stay close to the metal. ADO and Dapper promise to happily return multiple rowsets if your command contains multiple selects. See [here](http://stackoverflow.com/questions/12715620/how-do-i-return-multiple-result-sets-with-sqlcommand) and [here](http://stackoverflow.com/questions/6317937/dapper-net-and-stored-proc-with-multiple-result-sets) – bbsimonbb Oct 13 '16 at 10:11
  • Can you explain in more detail what kind of problem you have? Because Slapper.Automapper can handle Guids just fine. – Florian Haider Oct 13 '16 at 14:08
  • Really? See the link to the "How do I write one to many query" above? I got that working. I then changed the IDs in the tables to Guids and it stopped working. Should it continue to work? – niico Oct 13 '16 at 14:45
  • @user1585345 I don't just want multiple result sets - I want, say 10 objects back each with, say, 5 related items. – niico Oct 13 '16 at 14:50
  • Not sure about your usecase without seeing some code, but I have used Dapper & Slapper with Guids before and had no issues. – Florian Haider Oct 13 '16 at 15:11
  • @FlorianHaider See the linked article (all code included) - I get that to work with the int primary keys specified in the article, and not with Guids in their place. Do you think that should work OK then? – niico Oct 13 '16 at 15:12
  • Yes, if you correctly changed the DB column type as well as the according property in your POCO. – Florian Haider Oct 13 '16 at 15:19
  • I did that - it still returns 7 records - but they are all associated with contact3, not 3 separate contacts - each with 2 or 3 phone numbers – niico Oct 13 '16 at 15:22
  • Can you post the dataset you are testing with? – Florian Haider Oct 13 '16 at 15:30
  • @FlorianHaider done – niico Oct 13 '16 at 15:34
  • Looks ok. Can you also show your code and output? I justed tested your example and it is mapped correctly for me. – Florian Haider Oct 13 '16 at 19:59
  • @FlorianHaider done... – niico Oct 13 '16 at 22:27
  • 1
    You have varying upper and lowercases in your property names, e.g. ContactIdg and ContactIDg. Slapper does case sensitive mappings, see https://github.com/SlapperAutoMapper/Slapper.AutoMapper/issues/39 – Florian Haider Oct 14 '16 at 07:03
  • doh - thats it - if you leave an answer ill accept it thx. – niico Oct 14 '16 at 12:49

1 Answers1

5

You have varying upper and lowercases in your property names, e.g. ContactIdg and ContactIDg. Slapper does case sensitive mappings, see this issue.

Florian Haider
  • 1,892
  • 18
  • 23