/// <summary> /// Generates assocation keys in metadata. /// </summary> /// <param name="association">Association model.</param> /// <param name="backReference">Association side.</param> private void BuildAssociationMetadataKey(AssociationModel association, bool backReference) { // metadata model to update with keys var metadata = backReference ? association.TargetMetadata : association.SourceMetadata; // if metadata keys already specified in model, skip generation // (we don't generate them before this stage, so it means user generated them manually) if (metadata.ExpressionPredicate != null || metadata.QueryExpressionMethod != null || metadata.ThisKey != null || metadata.ThisKeyExpression != null || metadata.OtherKey != null || metadata.OtherKeyExpression != null) { return; } if (association.FromColumns == null || association.ToColumns == null || association.FromColumns.Length != association.ToColumns.Length || association.FromColumns.Length == 0) { throw new InvalidOperationException($"Invalid association configuration: association columns missing or mismatch on both sides of assocation."); } var thisColumns = backReference ? association.ToColumns : association.FromColumns; var otherColumns = !backReference ? association.ToColumns : association.FromColumns; var thisBuilder = !backReference ? _entityBuilders[association.Source] : _entityBuilders[association.Target]; var otherBuilder = backReference ? _entityBuilders[association.Source] : _entityBuilders[association.Target]; // we generate keys using nameof operator to get property name to have refactoring-friendly mappings // (T4 always used strings here) var separator = association.FromColumns.Length > 1 ? AST.Constant(",", true) : null; for (var i = 0; i < association.FromColumns.Length; i++) { if (i > 0) { // add comma separator metadata.ThisKeyExpression = AST.Add(metadata.ThisKeyExpression !, separator !); metadata.OtherKeyExpression = AST.Add(metadata.OtherKeyExpression !, separator !); } // generate nameof() expressions for current key column var thisKey = AST.NameOf(AST.Member(thisBuilder.Type.Type, _columnProperties[thisColumns [0]].Reference)); var otherKey = AST.NameOf(AST.Member(otherBuilder.Type.Type, _columnProperties[otherColumns[0]].Reference)); // append column name to key metadata.ThisKeyExpression = metadata.ThisKeyExpression == null ? thisKey : AST.Add(metadata.ThisKeyExpression, thisKey); metadata.OtherKeyExpression = metadata.OtherKeyExpression == null ? otherKey : AST.Add(metadata.OtherKeyExpression, thisKey); } }