private static TypeSpec TranslateTypeSpec(OS.TypeSpec t, Text Text, Dictionary <Object, TextRange> InnerPositions, Dictionary <Object, TextRange> Positions) { if (t.OnTypeRef) { var r = TypeSpec.CreateTypeRef((TypeRef)(t.TypeRef.VersionedName())); if (InnerPositions.ContainsKey(t)) { Positions.Add(r, InnerPositions[t]); } return(r); } else if (t.OnGenericTypeSpec && t.GenericTypeSpec.TypeSpec.OnTypeRef && t.GenericTypeSpec.TypeSpec.TypeRef.NameMatches("Optional") && t.GenericTypeSpec.ParameterValues.Count == 1) { var Parameter = t.GenericTypeSpec.ParameterValues.Single(); var InnerType = TranslateTypeSpec(Parameter, Text, InnerPositions, Positions); if (InnerType.OnTypeRef) { var r = TypeSpec.CreateOptional(InnerType.TypeRef); if (InnerPositions.ContainsKey(t)) { Positions.Add(r, InnerPositions[t]); } return(r); } } else if (t.OnGenericTypeSpec && t.GenericTypeSpec.TypeSpec.OnTypeRef && t.GenericTypeSpec.TypeSpec.TypeRef.NameMatches("List") && t.GenericTypeSpec.ParameterValues.Count == 1) { var Parameter = t.GenericTypeSpec.ParameterValues.Single(); if (Parameter.OnTypeRef && Parameter.TypeRef.NameMatches("Byte")) { var r = TypeSpec.CreateTypeRef((TypeRef)("Binary")); if (InnerPositions.ContainsKey(t)) { Positions.Add(r, InnerPositions[t]); } return(r); } else { var InnerType = TranslateTypeSpec(Parameter, Text, InnerPositions, Positions); if (InnerType.OnTypeRef) { var r = TypeSpec.CreateList(InnerType.TypeRef); if (InnerPositions.ContainsKey(t)) { Positions.Add(r, InnerPositions[t]); } return(r); } } } var oRange = InnerPositions.ContainsKey(t) ? InnerPositions[t] : TreeFormat.Optional <TextRange> .Empty; var FileRange = new FileTextRange { Text = Text, Range = oRange }; throw new InvalidEvaluationException("InvalidTypeSpec", FileRange, t); }
//在描述中可以在[]中使用如下几个标记 //在实体上 // CN:<Name> CollectionName // PK[C]:<Columns> PrimaryKey // C Clustered // UK[C]:<Columns> UniqueKey // C Clustered // NK[C]:<Columns> NonUniqueKey // C Clustered //在列上 // I Identity // N Nullable // P:<Params> TypeParameters, 例如字符串长度[P:50] //在导航属性上 // FK:<Columns>=<Columns> ForeignKey // RFK:<Columns>=<Columns> ReverseForeignKey // FNK:<Columns>=<Columns> ForeignNonUniqueKey 即当前键可指向多种物体,没有外键约束 // RFNK:<Columns>=<Columns> ReverseForeignNonUniqueKey 即目标键可指向多种物体,没有外键约束 // N Nullable,不能和FK同时使用 // FK和FNK只需要目标表上的键有索引,RFK和RFNK需要当前表和目标表的键都有索引 // //标记可以叠加,如[CN:Users][PKC:Id1, Id2],但FK、RFK、FNK、RFNK不能叠加 //外键中可有多个键,例如[FK:Id1, Id2=Id1, Id2] //索引列上可以标注减号表示递减,比如[PKC:Id1, Id2-] // //如果不存在CN,则默认使用<EntityName> //如果没有声明PK,则自动寻找名称为Id或者<EntityName>Id(不区分大小写)的列为[PK],但不会将该字段记为[I] //如果没有一个Key有C,则默认PK有C //如果一个非简单类型属性(导航属性)没有标明外键或反外键,则 // 1)如果有<Name>Id的列,且该列为简单类型,类型表的主键列数量为1,则将该字段标明为[FK:<Name>Id=<Type/ElementType>.<PrimaryKey>] // 2)如果类型表有一个<TableName>Id的列,且该列为简单类型,当前表的主键列数量为1,则将该字段标明为[RFK:<PrimaryKey>=<Type/ElementType>.<TableName>Id] //如果一个String类型的列上没有标记P,则报错 private void FillFieldAttribute(VariableDef f, Dictionary <String, EntityDef> Entities) { var t = f.Type; var IsColumn = false; if (t.OnTypeRef) { IsColumn = !Entities.ContainsKey((String)(t.TypeRef)); } else if (t.OnOptional) { IsColumn = !Entities.ContainsKey((String)(t.Optional)); } else if (t.OnList) { IsColumn = !Entities.ContainsKey((String)(t.List)); } else { throw new InvalidOperationException(); } FieldAttribute fa = null; var IsNullable = false; if (IsColumn) { var IsIdentity = false; String TypeParameters = null; foreach (var a in f.Attributes) { if (a.Key == "I") { IsIdentity = true; } else if (a.Key == "N") { IsNullable = true; } else if (a.Key == "P") { TypeParameters = String.Join(", ", a.Value); } else { throw new InvalidEvaluationException(String.Format("InvalidAttribute: {0}", a.Key), Positions.ContainsKey(f.Attributes) ? Positions[f.Attributes] : TreeFormat.Optional <FileTextRange> .Empty, a); } } //如果一个列上没有标记P,则自动添加[P:] if (TypeParameters == null) { TypeParameters = ""; } fa = FieldAttribute.CreateColumn(new ColumnAttribute { IsIdentity = IsIdentity, TypeParameters = TypeParameters }); } else { if (f.Attributes.Where(a => a.Key == "FK" || a.Key == "RFK" || a.Key == "FNK" || a.Key == "RFNK").Count() > 1) { throw new InvalidEvaluationException(String.Format("ConflictedAttributes: {0}", f.Name), Positions.ContainsKey(f.Attributes) ? Positions[f.Attributes] : TreeFormat.Optional <FileTextRange> .Empty, f); } foreach (var a in f.Attributes) { if (a.Key == "N") { IsNullable = true; continue; } var km = GetKeyMap(String.Join(", ", a.Value)); if (a.Key == "FK") { var IsReverse = false; var IsUnique = true; var ThisKey = km.ThisKey; var OtherKey = km.OtherKey; fa = FieldAttribute.CreateNavigation(new NavigationAttribute { IsReverse = IsReverse, IsUnique = IsUnique, ThisKey = ThisKey, OtherKey = OtherKey }); } else if (a.Key == "RFK") { var IsReverse = true; var IsUnique = true; var ThisKey = km.ThisKey; var OtherKey = km.OtherKey; fa = FieldAttribute.CreateNavigation(new NavigationAttribute { IsReverse = IsReverse, IsUnique = IsUnique, ThisKey = ThisKey, OtherKey = OtherKey }); } else if (a.Key == "FNK") { var IsReverse = false; var IsUnique = false; var ThisKey = km.ThisKey; var OtherKey = km.OtherKey; fa = FieldAttribute.CreateNavigation(new NavigationAttribute { IsReverse = IsReverse, IsUnique = IsUnique, ThisKey = ThisKey, OtherKey = OtherKey }); } else if (a.Key == "RFNK") { var IsReverse = true; var IsUnique = false; var ThisKey = km.ThisKey; var OtherKey = km.OtherKey; fa = FieldAttribute.CreateNavigation(new NavigationAttribute { IsReverse = IsReverse, IsUnique = IsUnique, ThisKey = ThisKey, OtherKey = OtherKey }); } else { throw new InvalidEvaluationException(String.Format("InvalidAttribute: {0}", a.Key), Positions.ContainsKey(f.Attributes) ? Positions[f.Attributes] : TreeFormat.Optional <FileTextRange> .Empty, a); } } if (fa == null) { fa = FieldAttribute.CreateNavigation(null); } } if (IsNullable && !t.OnOptional) { f.Type = TypeSpec.CreateOptional(t.TypeRef); if (Positions.ContainsKey(t)) { Positions.Add(f.Type, Positions[t]); } } f.Attribute = fa; }