我正在定制验证消息。它使用messageTemplates属性工作正常。但是它使用%displayName%来呈现属性的名称,我无法找到如何覆盖此值?反正有吗?
答案 0 :(得分:13)
我也想这样做,但我想使用EF模型中的[DisplayName]属性。在我找到一种我认为可以分享的方式后,我找不到任何有这样做的例子。
首先,我扩展了从BreezeController返回的元数据:
[HttpGet]
public string Metadata()
{
// Extend metadata with extra attributes
JObject metadata = JObject.Parse(contextProvider.Metadata());
string nameSpace = metadata["schema"]["namespace"].ToString();
foreach (var entityType in metadata["schema"]["entityType"])
{
string typeName = entityType["name"].ToString();
Type t = Type.GetType(nameSpace + "." + typeName);
foreach (var prop in t.GetProperties())
{
foreach (var attr in prop.CustomAttributes)
{
string name = attr.GetType().Name;
foreach (var p in entityType["property"])
{
if (prop.Name == p["name"].ToString()) {
if (attr.AttributeType.Name == "DisplayNameAttribute") {
DisplayNameAttribute a = (DisplayNameAttribute)Attribute.GetCustomAttribute(prop, typeof(DisplayNameAttribute));
p["displayName"] = a.DisplayName;
break;
}
}
}
}
}
}
return metadata.ToString();
}
然后我在元数据加载后添加了一些小的javascript来从Breeze想要找到它们的扩充元数据中查看显示名称。
manager.fetchMetadata().then(function (md) {
angular.forEach(md.schema.entityType, function (et) {
var etype = manager.metadataStore.getEntityType(et.name);
angular.forEach(et.property, function (p) {
var prop = etype.getProperty(p.name);
prop.displayName = p.displayName;
});
});
console.log("starting app");
angular.bootstrap($("#app"), ["app"]);
});
我正在使用角度,所以如果你不是,你可以忽略角度的东西,可能会得到这个想法。这似乎工作得很好。将其扩展到其他模型属性以及RegularExpression验证属性应该非常容易。我可能会继续努力。
仅供参考,这些代码中的一些代码未经过优化,可能会被重构,但有点漂亮,但我只是让它工作并认为我会分享。如果有人有任何更好的建议让我知道。希望Breeze将来允许以更受支持的方式扩展元数据。这似乎有点像黑客。
答案 1 :(得分:7)
这不是很好的记录,但你可以简单地设置' displayName'任何dataProperty上的属性,这将覆盖自动生成的显示名称,并将用于此属性的所有验证消息。所以
var custType = myEntityManager.metadataStore.getEntityType("Customer");
var dp = custType.getProperty("companyName");
dp.displayName = "My custom display name";
此外,请参阅"自定义消息模板"在本页底部:Breeze Validation
答案 2 :(得分:3)
按照jpcoder的建议请求,这里稍微改进了服务器部分:
JObject metadata = JObject.Parse(contextProvider.Metadata());
string nameSpace = metadata["schema"]["namespace"].ToString();
foreach (var entityType in metadata["schema"]["entityType"])
{
string typeName = entityType["name"].ToString();
Type t = Type.GetType(nameSpace + "." + typeName);
IEnumerable<JToken> metaProps = null;
if (entityType["property"].Type == JTokenType.Object)
metaProps = new[] { entityType["property"] };
else
metaProps = entityType["property"].AsEnumerable();
var props = from p in metaProps
let pname = p["name"].ToString()
let prop = t.GetProperties().SingleOrDefault(prop => prop.Name == pname)
where prop != null
from attr in prop.CustomAttributes
where attr.AttributeType.Name == "DisplayNameAttribute"
select new
{
Prop = p,
DisplayName = ((DisplayNameAttribute)Attribute.GetCustomAttribute(prop, typeof(DisplayNameAttribute))).DisplayName
};
foreach (var p in props)
p.Prop["displayName"] = p.DisplayName;
}
答案 3 :(得分:0)
查看http://www.breezejs.com/sites/all/apidocs/files/a40_entityMetadata.js.html#l1452,
可以通过将现有的“name”值重命名为nameOnServer(以满足getDataProperty调用)并将DisplayNameAttribute值作为“name”插入来改进吗?
答案 4 :(得分:0)
对服务器代码进行必要的更改是,如果您的模型类位于不同的程序集中,则无法使用
Type t = Type.GetType(nameSpace + "." + typeName);
您需要每种类型的命名空间(在元数据中),并且(我认为)使用BuildManager在不同的程序集中找到适当的类型。 cSpaceOSpaceMapping的映射可能会更优雅,但我没有时间研究不同的json格式选项。
JObject metadata = JObject.Parse(UnitOfWork.Metadata());
string EFNameSpace = metadata["schema"]["namespace"].ToString();
string typeNameSpaces = metadata["schema"]["cSpaceOSpaceMapping"].ToString();
typeNameSpaces = "{" + typeNameSpaces.Replace("],[", "]|[").Replace("[", "").Replace("]", "").Replace(",", ":").Replace("|", ",") + "}";
JObject jTypeNameSpaces = JObject.Parse(typeNameSpaces);
foreach (var entityType in metadata["schema"]["entityType"])
{
string typeName = entityType["name"].ToString();
string defaultTypeNameSpace = EFNameSpace + "." + typeName;
string entityTypeNameSpace = jTypeNameSpaces[defaultTypeNameSpace].ToString();
Type t = BuildManager.GetType(entityTypeNameSpace, false);
IEnumerable<JToken> metaProps = null;
if (entityType["property"].Type == JTokenType.Object)
metaProps = new[] { entityType["property"] };
else
metaProps = entityType["property"].AsEnumerable();
var props = from p in metaProps
let pname = p["name"].ToString()
let prop = t.GetProperties().SingleOrDefault(prop => prop.Name == pname)
where prop != null
from attr in prop.CustomAttributes
where attr.AttributeType.Name == "DisplayNameAttribute"
select new
{
Prop = p,
DisplayName = ((DisplayNameAttribute)Attribute.GetCustomAttribute(prop, typeof(DisplayNameAttribute))).DisplayName
};
foreach (var p in props)
{
p.Prop["displayName"] = p.DisplayName;
}
}
答案 5 :(得分:0)
JObject metadata = JObject.Parse(this._context.Metadata());
string EFNameSpace = metadata["schema"]["namespace"].ToString();
string typeNameSpaces = metadata["schema"]["cSpaceOSpaceMapping"].ToString();
typeNameSpaces = "{" + typeNameSpaces.Replace("],[", "]|[").Replace("[", "").Replace("]", "").Replace(",", ":").Replace("|", ",") + "}";
JObject jTypeNameSpaces = JObject.Parse(typeNameSpaces);
foreach (var entityType in metadata["schema"]["entityType"])
{
string typeName = entityType["name"].ToString();
string defaultTypeNameSpace = EFNameSpace + "." + typeName;
string entityTypeNameSpace = jTypeNameSpaces[defaultTypeNameSpace].ToString();
Type t = BuildManager.GetType(entityTypeNameSpace, false);
IEnumerable<JToken> metaProps = null;
if (entityType["property"].Type == JTokenType.Object)
metaProps = new[] { entityType["property"] };
else
metaProps = entityType["property"].AsEnumerable();
var props = from p in metaProps
let pname = p["name"].ToString()
let prop = t.GetProperties().SingleOrDefault(prop => prop.Name == pname)
where prop != null
from attr in prop.CustomAttributes
where attr.AttributeType.Name == "DisplayAttribute"
select new
{
Prop = p,
DisplayName = ((DisplayAttribute)Attribute.GetCustomAttribute(prop, typeof(DisplayAttribute))).Name
};
foreach (var p in props)
{
p.Prop["displayName"] = p.DisplayName;
}
}
return metadata.ToString();
答案 6 :(得分:0)
改善jpcoder的答案......
对我来说,我的大多数DisplayName更改都是用“大写字段字段名称”替换“PascalCaseFieldName”或“camelCaseFieldName”。因此,我应用默认函数来设置displayName,而不是在服务器上设置每个属性DisplayName。
最终结果要求的EF注释要少得多。我的TypeScript是:
manager.metadataStore.getEntityTypes().forEach(function (storeEntityType) {
if (!(storeEntityType instanceof breeze.EntityType)) {
throw new Error("loadExtendedMetadata found '" + storeEntityType
+ "' StructuralType that is not an EntityType (e.g. a ComplexType)");
}
var extEntityType = extendedMetadata.entitiesExtended.find((extendedEntityType) => {
return extendedEntityType.shortName + ":#" + extendedEntityType.nameSpace === storeEntityType.name;
});
(storeEntityType as breeze.EntityType).getProperties().forEach((storeProperty) => {
//Both NavigationProperty & DataProperty have displayName & nameOnServer properties
var storeDataProperty = <breeze.DataProperty>storeProperty;
var extProperty;
if (extEntityType) {
extProperty = extEntityType.propertiesExtented.find((extendedProperty) => {
return extendedProperty.name === storeDataProperty.nameOnServer;
});
}
//Smart default: nameOnServer "PascalCaseFieldName" or "camelCaseFieldName" converted to "Upper Case Field Name"
storeDataProperty.displayName = (extProperty && extProperty.displayName)
|| storeDataProperty.nameOnServer.replace(/^./, function (str) {
// first ensure the first character is uppercase
return str.toUpperCase();
// insert a space before all caps, remove first character (added space)
}).replace(/([A-Z])/g, " $1").substring(1);
});
});