使用breezejs和web api处理计算属性
我正在使用BreezeControllerAttribute使用Web API尝试BreezeJS。实体上的计算属性应如何公开?我发现唯一可靠的方法是创建从实体继承的中间DTO或使用投影。通常情况下,我会在这个场景中使用只读属性,但这些属性似乎会被忽略。当Breeze将JSON属性数据映射到实体时,它会忽略它无法识别的属性。这就是为什么服务器类的计算属性数据被丢弃的原因,即使您在连接的JSON中看到它们 幸运的是,您可以通过将属性注册为未映射属性来教Breeze识别该属性。我来教你怎么做。让我先介绍一下背景 背景 如果您的计算属性是由数据库计算的属性,那么Breeze客户端将“知道”您的计算属性。数据库备份的属性(常规属性和计算属性)作为映射属性在元数据中提取 但是在您的情况下(如果我理解正确的话),属性是在服务器端类的逻辑中定义的,而不是在数据库中定义的。因此,它不属于元数据中的映射属性。它对元数据是隐藏的。它是一个未映射的实例属性 我想你没有对序列化程序隐藏它。如果查看类查询的网络流量,可以看到计算的属性数据到达客户端。问题是Breeze在从这些查询结果“具体化”实体时忽略了它 举例说明 解决办法是 我修改了这个场景;您可以从GitHub获得该代码,也可以等待下一个Breeze版本 或者只需按照下面的代码进行操作,从NorthwindModel.cs中的使用breezejs和web api处理计算属性,breeze,asp.net-web-api,Breeze,Asp.net Web Api,我正在使用BreezeControllerAttribute使用Web API尝试BreezeJS。实体上的计算属性应如何公开?我发现唯一可靠的方法是创建从实体继承的中间DTO或使用投影。通常情况下,我会在这个场景中使用只读属性,但这些属性似乎会被忽略。当Breeze将JSON属性数据映射到实体时,它会忽略它无法识别的属性。这就是为什么服务器类的计算属性数据被丢弃的原因,即使您在连接的JSON中看到它们 幸运的是,您可以通过将属性注册为未映射属性来教Breeze识别该属性。我来教你怎么做。让我先
Employee
类的这段代码开始:
//未映射的服务器端计算属性
[NotMapped]//从实体框架隐藏;仍然序列化到客户端
公共字符串全名{
获取{返回LastName+
(String.IsNullOrWhiteSpace(FirstName)?“”:(“,“+FirstName”);}
}
下面是entityExtensionTests.js中的自动测试
测试(“未映射属性可以由服务器类的计算属性设置”,2,
函数(){
var store=cloneModuleMetadataStore();//克隆Northwind MetadataStore
//自定义雇员构造函数
var employeeCtor=函数(){
//“Fullname”是Employee类的服务器端计算属性
//对于新实体,此未映射属性将为空
//但将在查询物化期间为现有实体设置
this.FullName=“”;
};
//注册自定义构造函数
store.registerentitypector(“雇员”,employeeCtor);
var fullProp=store.getEntityType('Employee').getProperty('FullName');
确定(fullProp和fullProp.ISUNMAPTED,
“‘全名’应为注册后未映射的财产”);
var em=newEm(store);//helper使用此元数据存储创建管理器
var query=EntityQuery.from('Employees')。使用(em);
stop();//正在异步
query.execute().then(success).fail(handleFail).fin(start);
功能成功(数据){
var first=数据。结果[0];
var full=first.FullName();
//通过测试确认FullName属性具有一个值
ok(完整,“被查询的‘雇员’应该有一个全名(‘最后,第一’);它是“+完整);
}
});
您需要做的是在测试示例的这一小部分中:
var yourTypeCtor = function () {
this.calculatedProperty = ""; // "" or instance of whatever type is is supposed to be
};
// register your custom constructor
store.registerEntityTypeCtor("YourType", yourTypeCtor);
var yourTypeCtor=函数(){
this.calculatedProperty=“;/”或任何类型的实例应为
};
//注册自定义构造函数
store.registerEntityTypeCtor(“YourType”,yourTypeCtor);
我完全按照您描述的那样做了,但是计算属性并没有从查询结果中获取它的值,即使数据传输到客户端,它也总是空的。有什么隐藏的魔法吗?您描述为注释的行为未发生“/”,但将在查询具体化期间为现有实体设置“!我刚刚发现问题在于数据和定义的客户端属性之间的大小写不匹配。此示例按预期工作。@使用camelCase命名约定时似乎存在问题。它试图映射yourType.CalcProperty而不是yourType.CalcProperty。其他所有内容都是camelCase,但服务器发送Pascal Case,这似乎忽略了它:(为什么您认为camelCase约定有问题。它完全按照它所说的做:将PascalCase服务器端属性名称转换为客户端camelCase属性名称。当然,它会“误解”camelCase服务器属性名称;这些名称在其域中不存在。如果它们存在于您的域中,请编写一个满足您需要的自定义
NamingConvention
。这是一个非常简单的API,编写自定义NamingConvention
正是我们希望/期望您在您描述的情况下所做的。
test("unmapped property can be set by a calculated property of the server class", 2,
function () {
var store = cloneModuleMetadataStore(); // clones the Northwind MetadataStore
// custom Employee constructor
var employeeCtor = function () {
//'Fullname' is a server-side calculated property of the Employee class
// This unmapped property will be empty for new entities
// but will be set for existing entities during query materialization
this.FullName = "";
};
// register the custom constructor
store.registerEntityTypeCtor("Employee", employeeCtor);
var fullProp = store.getEntityType('Employee').getProperty('FullName');
ok(fullProp && fullProp.isUnmapped,
"'FullName' should be an unmapped property after registration");
var em = newEm(store); // helper creates a manager using this MetadataStore
var query = EntityQuery.from('Employees').using(em);
stop(); // going async
query.execute().then(success).fail(handleFail).fin(start);
function success(data) {
var first = data.results[0];
var full = first.FullName();
// passing test confirms that the FulllName property has a value
ok(full, "queried 'Employee' should have a fullname ('Last, First'); it is "+full);
}
});
var yourTypeCtor = function () {
this.calculatedProperty = ""; // "" or instance of whatever type is is supposed to be
};
// register your custom constructor
store.registerEntityTypeCtor("YourType", yourTypeCtor);