private void EmitOverridenNavigationProperties(StringBuilder builder, INamedTypeSymbol type) { //TODO: Support ALL foreign key scenarios. Right now only traditional attribute-based PropId and Prop pair scenarios are supported //Find all foreign key references and generate //the required overrides for their navigation properties. foreach (var prop in type .GetMembers() .Where(m => m.HasAttributeLike <ForeignKeyAttribute>() || m.HasAttributeExact <CompositeKeyHintAttribute>()) .Cast <IPropertySymbol>()) { //Special handling for composite key table references if (prop.Type.HasAttributeExact <CompositeKeyHintAttribute>() && prop.HasAttributeLike <CompositeKeyHintAttribute>()) { //TODO: Hack to get the key name //TODO: Is it ok for open generics to use the type args?? string keyTypeName = ComputeCompositeKeyTypeName(prop); string keyResolution = new TablePrimaryKeyParser().BuildCompositeKeyCreationExpression(prop, "base", keyTypeName); builder.Append($"[{nameof(IgnoreDataMemberAttribute)}]{Environment.NewLine}"); builder.Append($"public override {prop.Type.ToFullName()} {prop.Name} {Environment.NewLine}{{ get => {OriginalContextSymbol.GetFriendlyName()}.Instance.{new TableNameParser().Parse(prop.Type)}[{keyResolution}];{Environment.NewLine}"); builder.Append($"}}{Environment.NewLine}"); } else { IPropertySymbol navProperty = RetrieveNavigationPropertySymbol(prop); IPropertySymbol keyProperty = RetrieveNavigationKeyPropertySymbol(prop); builder.Append($"[{nameof(IgnoreDataMemberAttribute)}]{Environment.NewLine}"); builder.Append($"public override {navProperty.Type.ToFullName()} {navProperty.Name} {Environment.NewLine}{{ get => {OriginalContextSymbol.GetFriendlyName()}.Instance.{new TableNameParser().Parse(navProperty.Type)}[base.{keyProperty.Name}];{Environment.NewLine}"); builder.Append($"}}{Environment.NewLine}"); } } }
private void EmitSerializableInitializeMethod(StringBuilder builder) { builder.Append($"{Environment.NewLine}"); builder.Append($"public void {nameof(IGGDBFSerializable.Initialize)}({nameof(IGGDBFDataConverter)} converter){Environment.NewLine}{{{Environment.NewLine}"); foreach (var prop in EnumerateForeignCollectionProperties()) { string fieldName = ComputeCollectionPropertyBackingFieldName(prop); INamedTypeSymbol collectionElementType = (INamedTypeSymbol)ComputeCollectionElementType(prop); //TODO: Hack to get the key name //TODO: Is it ok for open generics to use the type args?? string keyTypeName = CreateKeyTypeForCollectionType(collectionElementType); string keyResolutionLambda = new TablePrimaryKeyParser().BuildKeyResolutionLambda(collectionElementType, keyTypeName); builder.Append($"{fieldName} = {nameof(GGDBFHelpers)}.{nameof(GGDBFHelpers.CreateSerializableCollection)}({keyResolutionLambda}, {prop.Name});{Environment.NewLine}"); } foreach (var prop in EnumerateOwnedTypeForeignCollectionProperties()) { string fieldName = ComputeCollectionPropertyBackingFieldName(prop); INamedTypeSymbol collectionElementType = (INamedTypeSymbol)ComputeCollectionElementType(prop); builder.Append($"{fieldName} = converter.{nameof(IGGDBFDataConverter.Convert)}<{collectionElementType.ToFullName()}, {ComputeOwnedTypeName(collectionElementType)}>({prop.Name});{Environment.NewLine}"); } builder.Append($"}}"); }
private void EmitModelKeyTypeSource(INamedTypeSymbol contextSymbol, GeneratorExecutionContext context, INamedTypeSymbol type) { string keyName = new TablePrimaryKeyParser().ParseSimple(type); StringBuilder builder = new StringBuilder(); UsingsEmitter usingsEmitter = new(); NamespaceDecoratorEmitter namespaceDecorator = new NamespaceDecoratorEmitter(new CompositeKeyTypeEmitter(keyName, type, Accessibility.Public), contextSymbol.ContainingNamespace.FullNamespaceString()); //If the type is another namespace we should import it //so we don't have to use fullnames. AddNamespacesForType(type, usingsEmitter); usingsEmitter.AddNamespaces(GGDBFConstants.DEFAULT_NAMESPACES); usingsEmitter.Emit(builder); namespaceDecorator.Emit(builder); string source = builder.ToString(); string hashMapKey = $"{keyName} {source.Substring(source.IndexOf('{'))}"; //Keys could be shared in cases of multiple contexts if (EmittedKeyTypes.Contains(hashMapKey)) { return; } EmittedKeyTypes.Add(hashMapKey); context.AddSource($"{contextSymbol.Name}_{keyName}", ConvertFileToNode(context, builder).ToString()); }