C # .Net Core Использование универсального свойства в базовом классе контроллера с использованием DbSet <TEntity>.FromSql - PullRequest
0 голосов
/ 28 июня 2018

У нас есть группа контроллеров, которые возвращают данные JSON для синхронизации сущностей через веб-API. Каждый объект данных имеет свой собственный контроллер и модель данных («Заказ, Товар, Клиент, ...») Итак, по сути, каждый контроллер использует один и тот же код. Единственное отличие - это имя пути контроллера / веб-API и модель данных, которая будет возвращена через JSON. Мы хотели бы иметь один базовый контроллер (BaseController.cs), который реализуют / расширяют все остальные контроллеры. Для этого нам нужно иметь виртуальное свойство «EntityType» или «EntityName» в базовом классе, которое определяется каждым дочерним классом контроллера. Тогда наш код для возврата данных не нужно повторять в каждом контроллере. Наша проблема в том, что мы не можем понять, как хранить / передавать / определять переменные типа или TEntity. И нам нужно это, чтобы выполнить основную часть нашего API метода «Get»:

Пример:

var returnValue = dbContext.Set<GetEntityModelClass()>().FromSql("EXEC dbo.[AJ_P_{0}_API]", GetEntityModelName()).ToList();

Мы реализуем GetEntityModelName () в классе BaseController.cs следующим образом:

public virtual string GetEntityName() { return null; }

и пример дочернего класса контроллера будет иметь следующий вид:

public override string GetEntityName() { return "Product"; }

Как мы можем сделать это для сопоставимого метода GetEntityModelClass (), который может передать значение, необходимое для вызова dbContext.Set ()?

В случае, если это поможет, вот большой пример нашего кода:

BaseController.cs
-----------------------------------------
namespace API.Controllers
{
    [Produces("application/json")]
    public class BaseController : Controller
    {

        // Returns the name of an entity as it is used in stored procedures, class names, etc...
        public virtual string GetEntityName()
        {
            return null;
        }
        // Return a type that can be utilized with the dbContext.Set<???>() call
        public virtual ??? GetEntityName()
        {
            return ???;
        }
        // SiteContext is the API site's data context.
        protected readonly SiteContext dbContext;
        public BaseController(SiteContext context)
        {
            dbContext = context;
        }

        [HttpGet("{token}")]
        public IActionResult Get([FromRoute] string token)
        {
            return Get(token);
        }
        public IActionResult Results(string token)
        { 
            if (!ModelState.IsValid) { return BadRequest(ModelState); }

            var returnValue = dbContext.Set<???GetEntityModel()???>().FromSql("EXEC dbo.[AJ_P_{0}_API] @Token={1}", GetEntityName(), token).ToList();

            return Ok(returnValue);
        }
    }
}

ProductController.cs
-----------------------------------------

namespace API.Controllers
{
    [Produces("application/json")]
    [Route("/Product")]
    public class ProductController : BaseController
    {
        public override string GetEntityName() {
            return "Product";
        }
        public override ???? GetEntityModel() {
            return ( ??? ProductModel type ??? )
        }

        public ProductController(SiteContext context) : base(context) { }

    }
}

1 Ответ

0 голосов
/ 29 июня 2018

Я не фанат базового базового контроллера. Однако вы можете сделать контроллер универсальным, принимая желаемый тип объекта в качестве аргумента типа. это должно решить вашу проблему.

Использование вашего образца контроллера

[Produces("application/json")]
public abstract class BaseController<TEntity, TModel> : Controller
    where TEntity : class 
    where TModel : class {

    // Returns the name of an entity as it is used in stored procedures, class names, etc...
    protected virtual string GetEntityName() {
        return typeof(TEntity).Name;
    }

    // SiteContext is the API site's data context.
    protected readonly SiteContext dbContext;
    protected BaseController(SiteContext context) {
        dbContext = context;
    }

    [HttpGet("{token}")]
    public IActionResult Get([FromRoute] string token) {
        return GetInternal(token);
    }

    protected abstract TModel Map(TEntity entity);

    protected virtual IActionResult GetInternal(string token)  
        if (!ModelState.IsValid) { return BadRequest(ModelState); }
        var sql = string.Format("EXEC dbo.[AJ_P_{0}_API] @Token", GetEntityName());
        var entities = dbContext.Set<TEntity>().FromSql(sql, token).ToList();
        var returnValue = entities.Select(Map);
        return Ok(returnValue);
    }
}

Производные контроллеры просто предоставят аргумент типа.

[Produces("application/json")]
[Route("[controller]")]
public class ProductController : BaseController<Product, ProductModel> {

    public ProductController(SiteContext context) : base(context) { }

    protected override ProductModel Map(Product entity) {
        return new ProductModel {
            Property1 = entity.Property1,
            //...
            PropertyN = entity.PropertyN,
        }
    }
}
...