Export to GitHub

dapper-dot-net - issue #50

Suggestion for automatic multi-mapping


Posted on Jul 20, 2011 by Happy Bear

Is any work planned to optionally auto-multi-map based off the AssociationAttribute (or similar)? Or is this completely off the table in order to stay with POCO or for some other reason?

Nature of relation would be relatively easy (for 1-1, 1-n at least) to determine (check for IEnumerable<T>/T on involved types)

Manually doing this is kind of tedious (foot work, identity tracking, LOC), especially for multiple joins. Even though it may be reusable in a limited fashion in the simple cases.

Example for the attribute usage:

[Association("OtherEntityName", "ThisKey", "OtherKey")]

A first step would not even need caching as it pays in terms of productivity.

I'll do it myself eventually if no one else will do it. But not in the coming months. Just asking :-)

PS: AssociationAttribute is stashed away in various DLLs and various forms across framework versions. But why not just copy it into Dapper for .NET < 4 and keep to the System.ComponentModel.DataAnnotations namespace for .NET 4, which seems useful in and of itself.

Comment #1

Posted on Jul 25, 2011 by Grumpy Rhino

I have been thinking about this, can you provide a comprehensive sample on how you think this should work

Comment #2

Posted on Dec 2, 2011 by Helpful Bear

What about limitless multi mapping?!?

Because it seems that you are doing something that should be done in a query or stored procedure in the database

In my project I have a HUGE quantity of data that must be returned from the database for every query.

So, I have developed, with the help of reflection, some extensions to the IDataReader and IDataRecord that can transform this kind of SELECT:

SELECT T.TeamID ,T.Name ,T.FullName ,M.MediaID AS Emblem_MediaID ,M.Url AS Emblem_Url ,C.AreaID AS Country_AreaID ,C.Name AS Country_Name ,F.MediaID AS Country_Photo_MediaID ,F.Url AS Country_Photo_Url ... FROM Team T INNER JOIN Media M... INNER JOIN Area C... INNER JOIN Media F... ...

Into a POCO like this one:

public partial class Team
{
  public int TeamId { get; set; }
  public string Name { get; set; }
  public string FullName { get; set; }

  public Area Country { get; set; }
  public Media Emblem { get; set; }

}

How? By splitting the strings with "_" and discovering on-the-fly if the property exists, its type, and if it is a simple or complex one like another POCO.

And has you can see, there are other POCO's involved like Area or Media.

Can you do this FASTER? Because its done every single time I get data from the database, and the example is just that. Multiply the columns returned by 10 or 20 and add other result sets and you can start to see the real picture.

And to be honest, I'm not that brilliant to change dapper...

If nobody answers this here I'm going to escalate it into a new issue.

Thanks in advance dudes

Comment #3

Posted on Jul 18, 2012 by Swift Monkey

Add unlimited multimapping and you'll have the perfect micro orm!

Comment #4

Posted on Jul 20, 2012 by Massive Bear

If anybody's interested, I can submit a pull request for my implementation of "unlimited" multimapping...

Comment #5

Posted on Jul 20, 2012 by Happy Giraffe

Definitely interested...that would be a great addition...

Comment #6

Posted on Jul 20, 2012 by Massive Bear

Ok, it's different to sdsilve's implementation as it still users Dapper's internals methods. I'll get a pull request submitted within the next 24 hours.

If Sam/Marc are watching, they may want to take a look as I could do with their judgment as to any potential perf issues etc.

Cheers

Comment #7

Posted on Jul 20, 2012 by Swift Monkey

Same as #5!! Very interested!

Comment #8

Posted on Jul 20, 2012 by Helpful Bear

Me to, although, as mal.earnest wrote and well, my problem is slightly different, because I must be able to UNFLAT unlimited column names, into Objects and Props, by splitting them on a '_' char, instead of splitting by any given column.

Using reflection in real time becomes slower than desired.

Another example: HomeTeam_Stadium_Country_AreaId

I'm looking at ValueInjector because its a bit faster than my own code, but it still has the same problem, it uses real time refection mapping.

Trying to figure out if I can cache something.

Comment #9

Posted on Jul 20, 2012 by Massive Bear

Is the purpose of aliasing and splitting on the '_' character purely to get around running out of generic parameters (i.e. )?

If so, then I think your issue is the same as mine where I ran out because of many JOINs to related entities.

In a nutshell, my solution is (excusing any typos):

SELECT T.TeamID ,T.Name ,T.FullName ,M.MediaID ,M.Url ,C.AreaID ,C.Name ,F.MediaID ,F.Url ... FROM Team T INNER JOIN Media M... INNER JOIN Area C... INNER JOIN Media F... ...

var team = Query( sql, new Type[] { typeof(Media), typeof(Area), ..., typeof(Media) }, (team, entities) => { team.TheMedia1 = (Media)entities[0]; team.TheMedia1.TheArea = (Area)entities[1]; ... team.TheMedia1 = (Media)entities[14]; return team; } ).FirstOrDefault();

"team" would then be the "full" object-graph.

Does that sound like it fits your needs? As I say, it's using all of the Dapper internals and so shouldn't add any extra overhead - apart from the "late-binding" required casting in the mapping function which should be negligible, but necessary for the "unlimited" nature...

Mal

Comment #10

Posted on Jul 20, 2012 by Massive Bear

Sorry... forgot:

splitOn: "MediaID,AreaId,...,MediaId"

Mal

Comment #11

Posted on Jul 20, 2012 by Massive Bear

Reading through skarmans initial post at the top of the issue, I think it should then be relatively easy for him to apply his own attribute based automatic mapping generation by passing the required types and employing some custom mapper code...

Mal

Comment #12

Posted on Jul 20, 2012 by Helpful Bear

I'm sorry for this :)

Real case scenario example bellow:

SELECT CompetitionID, M.MatchID, FixtureDate, FixtureTime, StartTime, Status_Name, Status_Value, Period_Name, Period_Value, WinnerTeamID, HomeTeamScore, HomeTeamPenaltiesScore, AwayTeamScore, AwayTeamPenaltiesScore, Attendance, Stadium_StadiumID, Stadium_Name, Stadium_Country_AreaID, Stadium_Country_Name, Stadium_Country_Initials, Stadium_Location, HomeTeam_TeamID, HomeTeam_Name, HomeTeam_FullName, HomeTeam_OfficialName, HomeTeam_Initials, HomeTeam_Tags, HomeTeam_Organization_OrganizationID, HomeTeam_HomeColor, HomeTeam_AwayColor, HomeTeam_Emblem_MediaID, HomeTeam_Emblem_Width, HomeTeam_Emblem_Height, HomeTeam_Emblem_Url, HomeTeam_Emblem_AlternateUrl, HomeTeam_Country_AreaID, HomeTeam_Country_Name, HomeTeam_Country_Initials, HomeTeam_Country_Photo_MediaID, HomeTeam_Country_Photo_Width, HomeTeam_Country_Photo_Height, HomeTeam_Country_Photo_Url, HomeTeam_Country_Photo_AlternateUrl, HomeTeam_HomeKit_MediaID, HomeTeam_HomeKit_Width, HomeTeam_HomeKit_Height, HomeTeam_HomeKit_Url, HomeTeam_HomeKit_AlternateUrl, AwayTeam_TeamID, AwayTeam_Name, AwayTeam_FullName, AwayTeam_OfficialName, AwayTeam_Initials, AwayTeam_Tags, AwayTeam_Organization_OrganizationID, AwayTeam_HomeColor, AwayTeam_AwayColor, AwayTeam_Emblem_MediaID, AwayTeam_Emblem_Width, AwayTeam_Emblem_Height, AwayTeam_Emblem_Url, AwayTeam_Emblem_AlternateUrl, AwayTeam_Country_AreaID, AwayTeam_Country_Name, AwayTeam_Country_Initials, AwayTeam_Country_Photo_MediaID, AwayTeam_Country_Photo_Width, AwayTeam_Country_Photo_Height, AwayTeam_Country_Photo_Url, AwayTeam_Country_Photo_AlternateUrl, AwayTeam_HomeKit_MediaID, AwayTeam_HomeKit_Width, AwayTeam_HomeKit_Height, AwayTeam_HomeKit_Url, AwayTeam_HomeKit_AlternateUrl, HomeTeamSlot_CompetitionID, HomeTeamSlot_Position, HomeTeamSlot_Name, HomeTeamSlot_MatchID, AwayTeamSlot_CompetitionID, AwayTeamSlot_Position, AwayTeamSlot_Name, AwayTeamSlot_MatchID, MatchSet_Value, MatchSet_Name, LiveCoverage, Aggregate_MatchID, Aggregate_WinnerTeamID, Aggregate_HomeTeamScore, Aggregate_AwayTeamScore FROM Views.Match M INNER JOIN @Matches FM ON FM.MatchID = M.MatchID

Comment #13

Posted on Jul 20, 2012 by Swift Monkey

I think both Mal and Sergio are talking about the same. I think with both solutions you can build a graph of unlimited deep and extension, but I prefer Mal's one because it doesn't introduce the requirement of using underscores (If I understand...)

Comment #14

Posted on Jul 20, 2012 by Helpful Bear

As you can see Mal, the amount of flatten data is huge, and given that, your solution seems a bit cumbersome for me. I'm prototyping a solution with a colleague, that uses ValueInjecter to unflat the data. Maybe we can create an extension for Dapper.

I'll keep you guys posted.

Comment #15

Posted on Jul 20, 2012 by Massive Bear

Yes, I think we are both along the same lines, although Sergio's issue is over and above "unlimited" mapping as it looks like he can't do anything about the aliased column names...

...or can you, segio? I mean, is ditching the view and just executing the SQL without the column aliases feasible? If so, then that would mean that my solution should work out-of-the-box for you...?

Mal

Comment #16

Posted on Jul 20, 2012 by Helpful Bear

Well toledoma... the real problem is the fact that the multimapping code would be so huge, that I would prefer not using dapper, to be honest.

Not to mention the fact that I do not have Table handles, I would have to use object names etc... to much complication.

Not to mention I have dozens of Stored Procs with different selects.

It's fine when you have simple objects to move around, but in my case it's just a complete overkill.

Comment #17

Posted on Jul 20, 2012 by Massive Bear

No worries, Sergio - keep us posted though! :)

Thanks,

Mal

Comment #18

Posted on Jul 30, 2012 by Quick Elephant

Here is my vote on limitless multi-mapping...really interested in unlimited mutimapping

Comment #19

Posted on Jul 30, 2012 by Happy Elephant

I am looking forward for unlimited multi-mapping solution, I have started using it, and reach a point where I need more than five mappings. THe DB used in project is very flat in nature and cannot be normalized (product DB).I need more objects to be filled from SP.

Comment #20

Posted on Jul 30, 2012 by Massive Bear

Please see my pull request for my implementation for this. There's an issue with the .Query<> method at the moment, but the .Read<> method works fine.

https://github.com/SamSaffron/dapper-dot-net/pull/44

Comment #21

Posted on Aug 9, 2012 by Quick Elephant

Cool...this actually kills two of my tasks...easier to abstract dapper now. I will not have multiple overloaded methods and multi-mapping more than 5 types. May we know when is this scheduled for release? Thanks a ton.

Comment #22

Posted on Aug 9, 2012 by Massive Bear

That's great - and exactly why I made the changes as I needed to drive Dapper in an abstract way without having to hand-code the multi-mapping for each of my entities. In many cases the were > 10 entities involved.

I'm running the code in the pull request without issue now although I'm hoping Marc will cast his eye over it soon and hopefully merge it into the main branch.

Mal

Comment #23

Posted on Nov 6, 2012 by Quick Elephant

Hello - was this included in 1.12 release? I don't see it in release notes?

Thanks, Mani

Comment #24

Posted on Nov 28, 2012 by Massive Rhino

Im really interested as i have to multimap more than ten tables for my project. When will it be included?

Comment #25

Posted on Nov 28, 2012 by Massive Bear

I've been successfully using the code in my pull request for some time now. Have a look at the tests in that pull request for an example of its use.

Maybe add a comment to my pull request to see if it'll get pushed into the main branch soon.

https://github.com/SamSaffron/dapper-dot-net/pull/44

Mal

Status: New

Labels:
Type-Defect Priority-Medium