zzzprojects / Bulk-Operations

C# SQL Bulk Operations | High-performance C# bulk insert, update, delete and merge for SQL Server, SQL Azure, SQL Compact, MySQL, and SQLite.
https://bulk-operations.net
142 stars 36 forks source link

Giving Composite key of table and Registering the Mapping using DapperPlusManager #35

Closed vaibhavrmore1 closed 6 years ago

vaibhavrmore1 commented 6 years ago

Using code snippet as below, they are throwing exceptions.

Code Snippet 1 : Trying to map Composite key of the table using "Key". DapperPlusManager.Entity<Tab>() Table("tbl_tab") .Map(x => x.Id, "tab_id") .Map(x => x.ScreenId, "Screen_id") .Map(x => x.Name, "tab_name") .Key(x => new { x.Id, x.ScreenId}) .InsertIfNotExists(); connection.BulkInsert(insertTabs)

Error : It says, An error occurred while resolving mapping by name.

Code Snippet 2: I am trying register the mapping in the constructor of the class where I am using it. as follows: DapperPlusManager.Entity<Tab>().Map(new TabEntityMapper());

where TabEntityMapper is as below:

public class TabEntityMapper: DapperPlusEntityMapper<Tab>
    {
        public SectionAccessBEEntityMapper()
        {
            Table("tbl_tab");
            Map(x => x.Id, "tab_id");
            Map(x => x.ScreenId, "Screen_id");
            Map(x => x.Name, "tab_name");
            InsertIfNotExists();
         }
    }

Error : An error occurred while retrieving informationtable information.
           Inner-exception:Invalid object name 'tbl_tab'.

Is there any other way to map Composite key of the table and register the mapping of the table at program start? Or else something wrong is there in above code snippet? Please help.

JonathanMagnan commented 6 years ago

Hello @vrm1995 ,

Thank you for reporting, we will look at it and create a similar scenario.

Best Regards,

Jonathan

JonathanMagnan commented 6 years ago

Hello @vrm1995 ,

One way to solve it is including the alias in the Key mapping.

For example:

DapperPlusManager.Entity<Tab>().Table("tbl_tab")
    .Map(x => x.Id, "tab_id")
    .Map(x => x.ScreenId, "Screen_id")
    .Map(x => x.Name, "tab_name")
    .Key(x => new {tab_id = x.Id, Screen_id = x.ScreenId})
    .InsertIfNotExists();

We are currently looking about the reason why we don't support .Key(x => new { x.Id, x.ScreenId}) as you first did. It seems that very little code would be needed to add (one line), so we need to double check the reason why we never did it yet.

JonathanMagnan commented 6 years ago

Hello @vrm1995 ,

Another way to map multi-key with the alias is only using the Key method

DapperPlusManager.Entity<Tab>().Table("tbl_tab")
    .Key(x => x.Id, "tab_id")
    .Key(x => x.ScreenId, "Screen_id")
    .Map(x => x.Name, "tab_name")

We have investigated the reason why we cannot support the first example you provided. I believe it could be possible but for some backward compatibility reason, it will not be as simple as I thought initially (several unit tests was broken for all the same reasons).

Let me know if one of the two solutions provided is enough for you.

Best Regards,

Jonathan

vaibhavrmore1 commented 6 years ago

Thanks @JonathanMagnan for looking into this.

I will try out both approaches and will continue and let you know if any discrepancies. Also, please can you help me out second question mentioned above.

Thanks, Vaibhav

vaibhavrmore1 commented 6 years ago

Hello @JonathanMagnan ,

Thanks for the information. Both the ways mentioned above are working fine for me.

Regarding the second concern, I tried as below which is working fine.

DapperPlusManager.Entity<Tab>().Table("tbl_tab").Map(new TabEntityMapper()).InsertIfNotExists();

where TabEntityMapper has only below content.

public class TabEntityMapper: DapperPlusEntityMapper<Tab>
    {
        public TabEntityMapper()
        {

            Map(x => x.Id, "tab_id");
            Map(x => x.ScreenId, "Screen_id");
            Map(x => x.Name, "tab_name");

         }
    } 

I was able register entity using the constructor to avoid repetition of code and use bulk functions directly.

Still, is there way to put all content in single class including .Table, .Key, .Map and .InsertIfNotExists()?

So that registering is also simple and single class file is passed as parameter to DapperPlusManager. Please suggest.

Thanks, Vaibhav

JonathanMagnan commented 6 years ago

Hello @vrm1995 ,

To avoid mapping everywhere, I normally recommend using a static constructor in the class so the mapping is only done once. You can have several mapping by using a mapping key. So you can later use the mapping you want for the specific operation by providing this mapping key.

Here is an example:

using System.Collections.Generic;
using System.Windows.Forms;
using Z.Dapper.Plus;

namespace Z.Lab
{
    public partial class Form_Request_MultiKey_WithAlias : Form
    {
        public Form_Request_MultiKey_WithAlias()
        {
            InitializeComponent();

            var list = new List<Tab>();
            list.Add(new Tab() { Id = 1, ScreenId = 1, Name = "zzz"});

            using (var connection = My.ConnectionFactory())
            {
                connection.BulkInsert(list);

                connection.BulkInsert(MappingName.InsertIfNotExists.ToString(), list);
            }
        }

        public enum MappingName
        {
            InsertIfNotExists
        }

        public class Tab
        {
            static Tab()
            {
                // Default mapping
                DapperPlusManager.Entity<Tab>().Table("tbl_tab")
                    .Map(x => x.Name, "tab_name")
                    .Key(x => x.Id, "tab_id")
                    .Key(x => x.ScreenId, "Screen_id");

                // Insert if not exists mapping
                DapperPlusManager.Entity<Tab>(MappingName.InsertIfNotExists.ToString()).Table("tbl_tab")
                    .Map(x => x.Name, "tab_name")
                    .Key(x => x.Id, "tab_id")
                    .Key(x => x.ScreenId, "Screen_id")
                    .InsertIfNotExists();
            }

            public int Id { get; set; }
            public int ScreenId { get; set; }
            public string Name { get; set; }
        }
    }
}

Let me know if that's what you are looking for or/and if that helped you to achieve what you want to do.

Best Regards,

Jonathan

vaibhavrmore1 commented 6 years ago

@JonathanMagnan ,

The above mentioned way will also serve the purpose. But, in above case I will have to create the object of the class at least once.

Is there way where we can initialize mapping by adding map file.

The way I found FluentMapper :


            FluentMapper.Initialize(config =>
            {
                     config.AddMap(new TabFluentMapper());
            }); 

So, I can add all map files at once at common entrance point of the code.

Thanks,
Vaibhav
JonathanMagnan commented 6 years ago

There is no Initialize method.

But you can either call a static method that does all mappings or calls multiple static methods that will do some specific mapping.

Something like this:

using System.Collections.Generic;
using System.Windows.Forms;
using Z.Dapper.Plus;

namespace Z.Lab
{
    public partial class Form_Request_MultiKey_WithAlias : Form
    {
        public enum MappingName
        {
            InsertIfNotExists
        }

        public Form_Request_MultiKey_WithAlias()
        {
            InitializeComponent();

            TabFluentMapper.InitializeMapping();

            var list = new List<Tab>();
            list.Add(new Tab {Id = 2, ScreenId = 2, Name = "zzz"});

            using (var connection = My.ConnectionFactory())
            {
                connection.BulkInsert(list);

                connection.BulkInsert(MappingName.InsertIfNotExists.ToString(), list);
            }
        }

        public class Tab
        {
            public int Id { get; set; }
            public int ScreenId { get; set; }
            public string Name { get; set; }
        }

        public class TabFluentMapper
        {
            public static void InitializeMapping()
            {
                // Default mapping
                DapperPlusManager.Entity<Tab>().Table("tbl_tab")
                    .Map(x => x.Name, "tab_name")
                    .Key(x => x.Id, "tab_id")
                    .Key(x => x.ScreenId, "Screen_id");

                // Insert if not exists mapping
                DapperPlusManager.Entity<Tab>(MappingName.InsertIfNotExists.ToString()).Table("tbl_tab")
                    .Map(x => x.Name, "tab_name")
                    .Key(x => x.Id, "tab_id")
                    .Key(x => x.ScreenId, "Screen_id")
                    .InsertIfNotExists();
            }
        }
    }
}
vaibhavrmore1 commented 6 years ago

Thanks @JonathanMagnan , I am already going with above mentioned method. I have created static class and will call the common method to initialize all the mapping of entities.

Regards, Vaibhav

JonathanMagnan commented 6 years ago

Great ;)

Let me know if we can close this request.

Best Regards,

Jonathan

vaibhavrmore1 commented 6 years ago

Thanks, We can close the issue.

Regards, Vaibhav