使用breezejs和web api处理计算属性

使用breezejs和web api处理计算属性,breeze,asp.net-web-api,Breeze,Asp.net Web Api,我正在使用BreezeControllerAttribute使用Web API尝试BreezeJS。实体上的计算属性应如何公开?我发现唯一可靠的方法是创建从实体继承的中间DTO或使用投影。通常情况下,我会在这个场景中使用只读属性,但这些属性似乎会被忽略。当Breeze将JSON属性数据映射到实体时,它会忽略它无法识别的属性。这就是为什么服务器类的计算属性数据被丢弃的原因,即使您在连接的JSON中看到它们 幸运的是,您可以通过将属性注册为未映射属性来教Breeze识别该属性。我来教你怎么做。让我先

我正在使用BreezeControllerAttribute使用Web API尝试BreezeJS。实体上的计算属性应如何公开?我发现唯一可靠的方法是创建从实体继承的中间DTO或使用投影。通常情况下,我会在这个场景中使用只读属性,但这些属性似乎会被忽略。

当Breeze将JSON属性数据映射到实体时,它会忽略它无法识别的属性。这就是为什么服务器类的计算属性数据被丢弃的原因,即使您在连接的JSON中看到它们

幸运的是,您可以通过将属性注册为未映射属性来教Breeze识别该属性。我来教你怎么做。让我先介绍一下背景

背景 如果您的计算属性是由数据库计算的属性,那么Breeze客户端将“知道”您的计算属性。数据库备份的属性(常规属性和计算属性)作为映射属性在元数据中提取

但是在您的情况下(如果我理解正确的话),属性是在服务器端类的逻辑中定义的,而不是在数据库中定义的。因此,它不属于元数据中的映射属性。它对元数据是隐藏的。它是一个未映射的实例属性

我想你没有对序列化程序隐藏它。如果查看类查询的网络流量,可以看到计算的属性数据到达客户端。问题是Breeze在从这些查询结果“具体化”实体时忽略了它

举例说明 解决办法是

我修改了这个场景;您可以从GitHub获得该代码,也可以等待下一个Breeze版本

或者只需按照下面的代码进行操作,从NorthwindModel.cs中的
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);