Use the OData Singleton mode in ASP. NET Web APIs, apiodata
We have added support for Singleton Mode Since OData v4. We don't need to obtain an EDM every time based on the primary key, just like using Singleton mode in C. The implementation method generally takes two steps:
1. Add the [Singleton] feature to the navigation attribute for implementing the Singleton mode.
2. Use builder. Singleton <SomeModel> ("SomeModels") to create SingletonConfiguration <SomeModel> During EDM configuration.
Start with the model.
public class Employee{ public int ID { get; set; } public string Name { get; set; } [Singleton] public Company Company { get; set; }}public enum CompanyCategory{ IT = 0, Communication = 1, Electronics = 2, Others = 3}public class Company{ public int ID { get; set; } public string Name { get; set; } public Int64 Revenue { get; set; } public CompanyCategory Category { get; set; } public List<Employee> Employees { get; set; }}
As mentioned above, there is a one-to-many relationship between Company and Employee. we add the [Singleton] feature to the Compnay navigation attribute of Employee, which means we want to use the Singleton mode on Company.
Configure WebApiConfig as follows:
public static class WebApiConfig{ public static void Register(HttpConfiguration config) { ... config.MapODataServiceRoute("ODataRoute", "odata", GetEdmModel()); } public static IEdmModel GetEdmModel() { ODataConventionModelBuilder builder = new ODataConventionModelBuilder(); EntitySetConfiguration<Employee> employeesConfiguration = builder.EntitySet<Employee>("Employees"); EntityTypeConfiguration<Employee> employeeTypeConfiguration = employeesConfiguration.EntityType; employeeTypeConfiguration.Action("ResetDataSource"); SingletonConfiguration<Company> companiesConfiguration = builder.Singleton<Company>("Umbrella"); companiesConfiguration.EntityType.Action("ResetDataSource"); companiesConfiguration.EntityType.Function("GetEmployeesCount").Returns<int>(); builder.Namespace = "Hello"; return builder.GetEdmModel(); }}
Above, the builder. Singleton <Company> ("Umbrella") method creates a SingletonConfiguration <Company> type instance, which is the way EDM implements a Singleton.
UmbrellaController of Company
Let's look at the Controller corresponding to Company, which is roughly as follows:
public class UmbrellaController : ODataController{ public static Company Umbrella; static UmbrellaController() { InitData(); } private static void InitData() { Umbrella = new Company() { ID = 1, Name = "Umbrella", Revenue = 1000, Category = CompanyCategory.Communication, Employees = new List<Employee>() }; } ... [HttpPost] public IHttpActionResult ResetDataSourceOnCompany() { InitData(); return StatusCode(HttpStatusCode.NoContent); } public IHttpActionResult GetEmployeesCount() { return Ok(Umbrella.Employees.Count); }}
Above, UmbrellaController's static Company-type Umbrella can be obtained globally. ResetDataSourceOnCompany: configure the companiesConfiguration of the single-instance EDM. entityType. action ("ResetDataSource"), GetEmployeesCount corresponds to the companiesConfiguration of the single-instance EDM. entityType. function ("GetEmployeesCount "). the Function of Returns <int>.
● Query
[EnableQuery]public IHttpActionResult Get(){ return Ok(Umbrella);}public IHttpActionResult GetRevenueFromCompany(){ return Ok(Umbrella.Revenue);}public IHttpActionResult GetName(){ return Ok(Umbrella.Employees);}
In the preceding example, GetRevenueFromCompany and GetName are used to obtain the attributes respectively. They must comply with the conventions, that is, "Get + attribute name ".
● Add
public IHttpActionResult Put(Company newCompany){ Umbrella = newCompany; return StatusCode(HttpStatusCode.NoContent);}
● Patch
public IHttpActionResult Patch(Delta<Company> item){ item.Patch(Umbrella); return StatusCode(HttpStatusCode.NoContent);}
● Create the Employees relationship on the Company
/// <Summary> /// create the relationship between Employees on the Company /// </summary> /// <param name = "navigationProperty"> </param> /// <param name = "link"> Empolyee uri </param> // <returns> </returns> [AcceptVerbs ("POST")] public IHttpActionResult CreateRef (string navigationProperty, [FromBody] Uri link) {// obtain the foreign key int employeeId = HelperFunction of the Employee. getKeyValue <int> (link); Employee employee = EmployeesController. employees. first (x => X. ID = employeeId); if (employee = null | navigationProperty! = "Employees") {return BadRequest ();} if (Umbrella. employees = null) {Umbrella. employees = new List <Employee> () {employee};} else {Umbrella. employees. add (employee);} return StatusCode (HttpStatusCode. noContent );}
Add an element to the Company's Employees set navigation attribute. The HelperFunction. GetKeyValue <int> () method is used to obtain the primary key of Empoyee in link. As follows:
Public static class HelperFunction {// obtain the primary key value public static TKey GetKeyValue <TKey> (Uri uri) {if (uri = null) {throw new ArgumentException ("uri ");} var rootPath = uri. absoluteUri. substring (0, uri. absoluteUri. lastIndexOf ('/') + 1); var odataUriParser = new ODataUriParser (WebApiConfig. getEdmModel (), new Uri (rootPath), uri); var odataPath = odataUriParser. parsePath (); var keySegment = odataPath. lastSegment as KeySegment; if (keySegment = null) {throw new InvalidOperationException ("The link does not contain a key");} return (TKey) keySegment. keys. first (). value ;}}
● Delete the Employees relationship on the Company
/// <Summary> /// Delete the link /// </summary> /// <param name = "relatedKey"> Primary Key of the Employee </param> /// <param name = "navigationProperty"> </param> // <returns> </returns> public IHttpActionResult DeleteRef (string relatedKey, string navigationProperty) {int key = int. parse (relatedKey); Employee employee = Umbrella. employees. first (x => x. ID = key); if (navigationProperty! = "Employees") {return BadRequest ();} Umbrella. Employees. Remove (employee); return StatusCode (HttpStatusCode. NoContent );}
In fact, it is to delete an Employee element in the Company set attribute Employees.
● Add an Employee element to the Company's Employees set.
/// <Summary> /// add an Employee from Compnay /// </summary> /// <param name = "employee"> </param> /// <returns> </returns> [HttpPost] public IHttpActionResult PostToEmployees ([FromBody] Employee) {EmployeesController. employees. add (employee); if (Umbrella. employees = null) {Umbrella. employees = new List <Employee> () {employee};} else {Umbrella. employees. add (employee);} return Created (employee );}
Unknown complaints from EmployeesController
Public class EmployeesController: ODataController {public static List <Employee> Employees; static EmployeesController () {InitData ();} private static void InitData () {Employees = Enumerable. range (0, 10 ). select (I => new Employee () {ID = I, Name = string. format ("Name {0}", I )}). toList ();} [EnableQuery] public IHttpActionResult Get () {return OK (Employees. asQueryable ();} [EnableQuery] public I HttpActionResult Get (int key) {return OK (Employees. where (e => e. ID = key);} public IHttpActionResult GetCompanyFromEmployee ([FromODataUri] int key) {var company = Employees. first (e => e. ID = key ). company; if (company = null) {return StatusCode (HttpStatusCode. notFound);} return OK (company);} public IHttpActionResult Post ([FromBody] Employee employee) {Employees. add (employee); return Created (Employee);} [AcceptVerbs ("PUT")] public IHttpActionResult CreateRef ([FromODataUri] int key, string navigationProperty, [FromBody] Uri link) {if (navigationProperty! = "Company") {return BadRequest ();} Employees. first (e => e. ID = key ). company = UmbrellaController. umbrella; return StatusCode (HttpStatusCode. noContent);} public IHttpActionResult DeleteRef ([FromODataUri] int key, string navigationProperty) {if (navigationProperty! = "Company") {return BadRequest ();} Employees. first (e => e. ID = key ). company = null; return StatusCode (HttpStatusCode. noContent);} public IHttpActionResult PutToCompany (int key, Company company) {var navigateCompany = Employees. first (e => e. ID = key ). company; Employees. first (e => e. ID = key ). company = company; if (navigateCompany. name = "Umbrella") {// reflect Singleton UmbrellaController. umbrella = navigateCompany;} else {return BadRequest ();} return StatusCode (HttpStatusCode. noContent);} public IHttpActionResult PatchToCompany (int key, Delta <Company> company) {var navigateCompan = Employees. first (e => e. ID = key ). company; company. patch (Employees. first (e => e. ID = key ). company); if (navigateCompan. name = "Umbrella") {company. patch (UmbrellaController. umbrella);} else {return BadRequest ();} return StatusCode (HttpStatusCode. noContent);} [HttpPost] public IHttpActionResult resetperformanceoncollectionofemployee () {InitData (); return OK ();}}