您的位置:首页 > 编程语言 > ASP

在ASP.NET Web API中使用OData的单例模式

2015-11-10 10:44 567 查看
从OData v4开始增加了对单例模式的支持,我们不用每次根据主键等来获取某个EDM,就像在C#中使用单例模式一样。实现方式大致需要两步:

1、在需要实现单例模式的导航属性上加上[Singleton]特性
2、在EDM配置的时候使用builder.Singleton<SomeModel>("SomeModels")来创建SingletonConfiguration<SomeModel>

首先还是从模型开始。

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


以上,Company和Employee存在1对多关系,我们在Employee的Compnay导航属性上加上了[Singleton]特性,也就意味着我们希望在Company上使用单例模式。

然后就在WebApiConfig中配置如下:

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


以上,builder.Singleton<Company>("Umbrella")方法创建SingletonConfiguration<Company>类型的实例,这是EDM实现单例的方式。

[b]Company对应的控制器UmbrellaController[/b]

再来看Company对应的控制器,大致如下:

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


以上,UmbrellaController提供的静态Company类型的Umbrella可以在全局获取。ResetDataSourceOnCompany对应配置单例EDM的companiesConfiguration.EntityType.Action("ResetDataSource")的Action,GetEmployeesCount对应配置单例EDM的companiesConfiguration.EntityType.Function("GetEmployeesCount").Returns<int>()的Function。

● 查询

[EnableQuery]
public IHttpActionResult Get()
{
return Ok(Umbrella);
}

public IHttpActionResult GetRevenueFromCompany()
{
return Ok(Umbrella.Revenue);
}

public IHttpActionResult GetName()
{
return Ok(Umbrella.Employees);
}


以上,GetRevenueFromCompany和GetName分别获取属性,要符合惯例,即"Get+属性名称"。

● 添加

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


● 创建Company上的Employees关系

/// <summary>
/// 创建Company上Employees的关系
/// </summary>
/// <param name="navigationProperty"></param>
/// <param name="link">Empolyee的uri地址</param>
/// <returns></returns>
[AcceptVerbs("POST")]
public IHttpActionResult CreateRef(string navigationProperty, [FromBody] Uri link)
{
//获取Employee的外键
int employeeId = HelperFunction.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);
}


其实就是往Company的Employees集合导航属性中添加一个元素。其中,HelperFunction.GetKeyValue<int>()方法用来获取link中Empoyee的主键。如下:

public static class HelperFunction
{
//获取主键值
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;
}
}


● 删除Company上的Employees关系

/// <summary>
/// 删除关系
/// </summary>
/// <param name="relatedKey">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);
}


其实就是删除Company的集合属性Employees中的一个Employee元素。

● 往Company的Employees集合里添加一个Employee元素

/// <summary>
/// 从Compnay处添加某个Employee
/// </summary>
/// <param name="employee"></param>
/// <returns></returns>
[HttpPost]
public IHttpActionResult PostToEmployees([FromBody] Employee employee)
{
EmployeesController.Employees.Add(employee);
if(Umbrella.Employees == null)
{
Umbrella.Employees = new List<Employee>() { employee };
}
else
{
Umbrella.Employees.Add(employee);
}
return Created(employee);
}


[b]EmployeesController不详诉[/b]

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 IHttpActionResult 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")
{
//体现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 ResetDataSourceOnCollectionOfEmployee()
{
InitData();
return Ok();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: