Изменить тип данных метода динамически / во время выполнения - PullRequest
0 голосов
/ 09 ноября 2019

У меня есть Sql DB с 40 таблицами, и я построил модели, представляющие каждую таблицу, я также использую Dapper в качестве своего ORM ...

Я строю свои операторы CRUD в DAL (уровне доступа к данным)это займет myModelObj (входящий через HTTPPost) и modelName (входящий через параметр URL)

У меня также есть метод (MyMapper), который сопоставит мои myModelObj с моими моделями -однако метод, который я создал, имеет тип object, который возвращает System.Object типов. Я хотел бы, чтобы метод возвращал модель и преобразовывал тип данных вызывающего метода динамически / во время выполнения, чтобы соответствоватьвозвращаемый тип модели ...

Мой код:

Контроллер

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;
    }
}

(В настоящее время) Тип данных, возвращаемый с MyMapper("User", {<Object from HTTP Post>}), равен System.Object, поскольку MyMapper относится к типу object

Я хочу, чтобы тип данных динамически изменялся в соответствии с моделью ...

MyMapper("User", {<Object from HTTP Post>}) => тип данных= User

Имейте в виду, что есть 40 различных таблиц / моделей, против которых я могу использовать CRUD, очевидно, я не буду знать, какая из них вызывается до времени выполнения ...

(для завершения примера) ... Я беру объект, возвращенный из MyMapper, и передаю его в connection.insert(...); (я изменил свой пост, чтобы показать это - посмотрите на DbOperation)

Есть предложения? Мысли?

1 Ответ

3 голосов
/ 10 ноября 2019

Если я понимаю ваш вопрос, вы пытаетесь вызвать сторонний (Dapper) универсальный метод без предварительного знания аргумента универсального типа, который обычно должен быть предоставлен во время компиляции.

Это может быть выполнено через Reflection . В вашем классе-обертке (который, я полагаю, вы называете «DbConnector») добавьте новый метод «InsertDynamicObject» и закодируйте его, чтобы использовать Reflection, чтобы найти определение метода, которое вы хотите вызвать. Затем вы можете вызвать MakeGenericMethod, передав параметры общего типа. Пример может выглядеть так:

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);
        }
    }
}

Вывод:

Inserting an object with type System.String

Вот ссылка на рабочий пример на DotNetFiddle: Ссылка

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...