简体   繁体   English

动态/在运行时更改方法数据类型

[英]Change method data type dynamically / at runtime

I have a Sql DB with 40 tables and I built models representing each table, I am also using Dapper as my ORM...我有一个带有 40 个表的 Sql 数据库,我构建了代表每个表的模型,我还使用 Dapper 作为我的 ORM ...

I am building my CRUD statements within a DAL (data access layer) that will take myModelObj (coming in via HTTPPost) and modelName (coming in via URL param)我正在 DAL(数据访问层)中构建我的 CRUD 语句,它将采用myModelObj (通过 HTTPPost 进入)和modelName (通过 URL 参数进入)

I also have a method ( MyMapper ) that will map my myModelObj to my models - however the method I created is of type object , which returns System.Object types - what I would like to have happen is the method return the model and convert the data type of the calling method, dynamically/at runtime, to match the model type being returned... I also have a method ( MyMapper ) that will map my myModelObj to my models - however the method I created is of type object , which returns System.Object types - what I would like to have happen is the method return the model and convert the调用方法的数据类型,动态/在运行时,以匹配正在返回的 model 类型...

My code:我的代码:

Controller Controller

private readonly IDbOperation _dbo;
...
...

public DataController(IDbOperation dboperation)
{
      _dbo = dboperation;
}

...

[HttpPost("create/{modelName}", Name = "Generic CRUD: Create Method")]
[Produces("application/json")]
public ActionResult Create([FromBody] JObject createObject, string modelName)
{
  try
  {
      ... ... ...

      object response = _dbo.CreateRecord(createObject, modelName);

// HTTP Post Body example
{
    "Fullname": "Juan Carlos",
    "Firstname": "Juan",
    "Lastname": "Carlos",
    "Salutation": "Dr.",
    "Age": 30,
    "CreatedOn": "2019-11-07T12:25:10"
}

DbOperation数据库操作

private readonly IDbConnector _dbConnector
...

public DbOperation(IDbConnector dbConnector)
{
      _dbConnector = dbConnector;
}

public JsonResult CreateRecord(JObject model, string modelName)
{
      ... ... ...
      var create = MyMapper(modelName, model); // <<<
      ... ...
      try
      {
            using (var connection = _dbConnector.GetMsSqlConnection())
            {
                 // https://dapper-tutorial.net/insert
                 var createdId = connection.Insert(create); 
                 ...
            }
      }
}

private object MyMapper(string modelName, JObject mod)
{
      switch (modelName.ToLower())
      {
           case "transaction":
                return JsonConvert.DeserializeObject<ModelRepoDTO.Transaction>(model.ToString());

           case "items":
                return JsonConvert.DeserializeObject<ModelRepoDTO.Items>(model.ToString());

           case "users":
                return JsonConvert.DeserializeObject<ModelRepoDTO.Users>(mod.ToString());
      ...
      ...
           default:
                _logger.Error("DataAccessLayer", "DbOperation", ">>> Mapping decision could not be made");
                break;
    }
}

DbConnector数据库连接器

public class DbConnector : IDbConnector
{
    private readonly string _connectionstring;

    public DbConnector(IConfiguration config)
    {
        _connectionstring = config.GetValue<string>("Connectionstring");
    }

    public SqlConnection GetMsSqlConnection()
    {
        SqlConnection conn = null;
        try
        {
            conn = new SqlConnection(_connectionstring);
            conn.Open();
            if (conn.State != ConnectionState.Open)
            {
                // throw error
            }
        }
        catch (Exception ex)
        {
            if (conn != null && conn.State == ConnectionState.Open)
            {
                conn.Close();
            }
            conn = null;
        }

        // return the connection
        return conn;
    }
}

(Currently) The data type coming back from MyMapper("User", {<Object from HTTP Post>}) is System.Object because MyMapper is of type object (当前)从MyMapper("User", {<Object from HTTP Post>})返回的数据类型是System.Object因为MyMapper的类型是object

What I want is to have the data type dynamically changed to match the model...我想要的是动态更改数据类型以匹配 model ...

MyMapper("User", {<Object from HTTP Post>}) => data type = User MyMapper("User", {<Object from HTTP Post>}) => data type = User

Keep in mind there are 40 different tables/models I can be CRUD'ing against, obviously I won't know which one is being called until runtime...请记住,我可以针对 40 个不同的表/模型进行 CRUD,显然我不会知道在运行时之前调用的是哪个表/模型......

(to complete the example) ...I take the object returned from MyMapper and pass it to connection.insert(...); (完成示例) ...我将 MyMapper 返回的MyMapper传递给connection.insert(...); (I modified my post to show this - look at DbOperation) (我修改了我的帖子以显示这一点 - 看看 DbOperation)

Any suggestions?有什么建议么? Thoughts?想法?

If I understand your question, you are attempting to call a third party (Dapper) generic method without foreknowledge of the generic type argument, which normally must be supplied at compile time.如果我理解您的问题,您正在尝试调用第三方(Dapper)泛型方法,而无需预知泛型类型参数,通常必须在编译时提供。

This can be accomplished via Reflection .这可以通过反射来完成。 In your wrapper class (which I believe you call "DbConnector") add a new method called "InsertDynamicObject" and code it to use Reflection to find the method definition that you wish to call.在您的包装器 class(我相信您称之为“DbConnector”)中添加一个名为“InsertDynamicObject”的新方法,并将其编码为使用反射来查找您希望调用的方法定义。 You can then call MakeGenericMethod, passing the generic type parameters.然后,您可以调用 MakeGenericMethod,传递泛型类型参数。 An example could look like this:一个示例可能如下所示:

namespace Dapper  //This is a stub for the Dapper framework that you cannot change
{
    class DbConnection
    {
        public void Insert<T>(T obj)
        {
            Console.WriteLine("Inserting an object with type {0}", typeof(T).FullName);
        }
    }
}

namespace MyProgram
{
    class DbConnector  //Here is your DbConnector class, which wraps Dapper
    {
        protected readonly Dapper.DbConnection _connection = new Dapper.DbConnection();

        public void InsertDynamicObject(object obj)
        {
            typeof(Dapper.DbConnection)
                .GetMethod("Insert")
                .MakeGenericMethod(new [] { obj.GetType() })
                .Invoke(_connection, new[] { obj });
        }
    }

    public class Program
    {
        public static void Main()
        {
            object someObject = "Test";  //This is the object that you deserialized where you don't know the type at compile time.

            var connector = new DbConnector();
            connector.InsertDynamicObject(someObject);
        }
    }
}

Output: Output:

Inserting an object with type System.String

Here is a link to a working example on DotNetFiddle: Link这是 DotNetFiddle 上一个工作示例的链接:链接

I think OP is trying to consume dapper insert method from Dapper's contrib lib.我认为 OP 正在尝试使用 Dapper 的 contrib lib 中的 dapper insert 方法。 Hence the generic create method.因此,通用的创建方法。 @Op am I understanding it right? @Op我理解对了吗?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM