简体   繁体   English

C#.Net Core利用DbSet在基本控制器类中利用通用属性 <TEntity> .FromSql

[英]C# .Net Core Utilize generic property in base controller class utilizing DbSet<TEntity>.FromSql

We have a group of controllers that return JSON data for to sync entities via a Web API. 我们有一组控制器,这些控制器返回JSON数据以通过Web API同步实体。 Each data entity has its own controller and data model ( "Order, Item, Customer, ..." ) So, this essentially has every controller using the exact same code. 每个数据实体都有其自己的控制器和数据模型(“ Order,Item,Customer ...”),因此,实质上每个控制器都使用完全相同的代码。 The only difference is name of the controller/web api path, and the data model that will be returned via JSON. 唯一的区别是控制器/ Web api路径的名称,以及将通过JSON返回的数据模型。 What we would like to do is have one base controller (BaseController.cs) that all other controllers implement/extend. 我们想要做的是拥有一个所有其他控制器都实现/扩展的基本控制器(BaseController.cs)。 To do this, we want to have a virtual "EntityType" or "EntityName" property in the base class that each child controller class defines. 为此,我们希望每个子控制器类定义的基类中都有一个虚拟的“ EntityType”或“ EntityName”属性。 Then, our code to return the data does not have to be repeated within every controller. 然后,不必在每个控制器中重复执行返回数据的代码。 Our problem is we can't figure out how to store/pass/define a "type" or "TEntity" variable. 我们的问题是我们无法弄清楚如何存储/传递/定义“类型”或“ TEntity”变量。 And we need this to execute the main part of our "Get" api method: 我们需要它来执行“ Get” api方法的主要部分:

Example: 例:

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

We implement GetEntityModelName() in the BaseController.cs class like this: 我们在BaseController.cs类中实现GetEntityModelName(),如下所示:

public virtual string GetEntityName() { return null; }

and an example of a child controller class would have the following: 子控制器类的示例将具有以下内容:

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

How can we do this for a comparable GetEntityModelClass() that could pass the value that dbContext.Set() call needs? 对于可传递dbContext.Set()调用所需值的可比较GetEntityModelClass(),我们如何做到这一点?

In case it helps, here is a larger sample of our code: 如果有帮助,这里是我们的代码的更大示例:

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

    }
}

I am not a fan of the generic base controller. 我不喜欢通用基本控制器。 You can however make the controller generic, taking the desired entity type as the type argument. 但是,您可以使控制器通用,将所需的实体类型作为类型参数。 that should solve your problem. 那应该可以解决您的问题。

Using your sample controller 使用样品控制器

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

Derived controllers will then simply provide the type argument. 然后派生的控制器将简单地提供type参数。

[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,
        }
    }
}

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

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