X Tutup
using System; using System.Diagnostics.CodeAnalysis; using System.Net.Security; using System.Security.Cryptography.X509Certificates; using System.Text.Json; using System.Text.Json.Nodes; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Npgsql.Internal; using Npgsql.Internal.ResolverFactories; using Npgsql.NameTranslation; using Npgsql.TypeMapping; using NpgsqlTypes; namespace Npgsql; /// /// Provides a simple API for configuring and creating an , from which database connections can be obtained. /// public sealed class NpgsqlDataSourceBuilder : INpgsqlTypeMapper { static UnsupportedTypeInfoResolver UnsupportedTypeInfoResolver { get; } = new(); readonly NpgsqlSlimDataSourceBuilder _internalBuilder; /// /// A diagnostics name used by Npgsql when generating tracing, logging and metrics. /// public string? Name { get => _internalBuilder.Name; set => _internalBuilder.Name = value; } /// public INpgsqlNameTranslator DefaultNameTranslator { get => _internalBuilder.DefaultNameTranslator; set => _internalBuilder.DefaultNameTranslator = value; } /// /// A connection string builder that can be used to configure the connection string on the builder. /// public NpgsqlConnectionStringBuilder ConnectionStringBuilder => _internalBuilder.ConnectionStringBuilder; /// /// Returns the connection string, as currently configured on the builder. /// public string ConnectionString => _internalBuilder.ConnectionString; internal static void ResetGlobalMappings(bool overwrite) => GlobalTypeMapper.Instance.AddGlobalTypeMappingResolvers([ overwrite ? new AdoTypeInfoResolverFactory() : AdoTypeInfoResolverFactory.Instance, new ExtraConversionResolverFactory(), new JsonTypeInfoResolverFactory(), new RecordTypeInfoResolverFactory(), new FullTextSearchTypeInfoResolverFactory(), new NetworkTypeInfoResolverFactory(), new GeometricTypeInfoResolverFactory(), new LTreeTypeInfoResolverFactory(), new CubeTypeInfoResolverFactory() ], static () => { var builder = new PgTypeInfoResolverChainBuilder(); builder.EnableRanges(); builder.EnableMultiranges(); builder.EnableArrays(); return builder; }, overwrite); static NpgsqlDataSourceBuilder() => ResetGlobalMappings(overwrite: false); /// /// Constructs a new , optionally starting out from the given . /// public NpgsqlDataSourceBuilder(string? connectionString = null) { _internalBuilder = new(new NpgsqlConnectionStringBuilder(connectionString)); _internalBuilder.ConfigureDefaultFactories = static instance => { instance.AppendDefaultFactories(); instance.AppendResolverFactory(new ExtraConversionResolverFactory()); instance.AppendResolverFactory(() => new JsonTypeInfoResolverFactory(instance.JsonSerializerOptions)); instance.AppendResolverFactory(new RecordTypeInfoResolverFactory()); instance.AppendResolverFactory(new FullTextSearchTypeInfoResolverFactory()); instance.AppendResolverFactory(new NetworkTypeInfoResolverFactory()); instance.AppendResolverFactory(new GeometricTypeInfoResolverFactory()); instance.AppendResolverFactory(new LTreeTypeInfoResolverFactory()); instance.AppendResolverFactory(new CubeTypeInfoResolverFactory()); }; _internalBuilder.ConfigureResolverChain = static chain => chain.Add(UnsupportedTypeInfoResolver); _internalBuilder.EnableTransportSecurity(); _internalBuilder.EnableIntegratedSecurity(); _internalBuilder.EnableRanges(); _internalBuilder.EnableMultiranges(); _internalBuilder.EnableArrays(); } /// /// Sets the that will be used for logging. /// /// The logger factory to be used. /// The same builder instance so that multiple calls can be chained. public NpgsqlDataSourceBuilder UseLoggerFactory(ILoggerFactory? loggerFactory) { _internalBuilder.UseLoggerFactory(loggerFactory); return this; } /// /// Enables parameters to be included in logging. This includes potentially sensitive information from data sent to PostgreSQL. /// You should only enable this flag in development, or if you have the appropriate security measures in place based on the /// sensitivity of this data. /// /// If , then sensitive data is logged. /// The same builder instance so that multiple calls can be chained. public NpgsqlDataSourceBuilder EnableParameterLogging(bool parameterLoggingEnabled = true) { _internalBuilder.EnableParameterLogging(parameterLoggingEnabled); return this; } /// /// Configures type loading options for the DataSource. /// public NpgsqlDataSourceBuilder ConfigureTypeLoading(Action configureAction) { _internalBuilder.ConfigureTypeLoading(configureAction); return this; } /// /// Configures OpenTelemetry tracing options. /// /// The same builder instance so that multiple calls can be chained. public NpgsqlDataSourceBuilder ConfigureTracing(Action configureAction) { _internalBuilder.ConfigureTracing(configureAction); return this; } /// /// Configures the JSON serializer options used when reading and writing all System.Text.Json data. /// /// Options to customize JSON serialization and deserialization. /// The same builder instance so that multiple calls can be chained. public NpgsqlDataSourceBuilder ConfigureJsonOptions(JsonSerializerOptions serializerOptions) { _internalBuilder.ConfigureJsonOptions(serializerOptions); return this; } /// /// Sets up dynamic System.Text.Json mappings. This allows mapping arbitrary .NET types to PostgreSQL json and jsonb /// types, as well as and its derived types. /// /// /// A list of CLR types to map to PostgreSQL jsonb (no need to specify ). /// /// /// A list of CLR types to map to PostgreSQL json (no need to specify ). /// /// /// Due to the dynamic nature of these mappings, they are not compatible with NativeAOT or trimming. /// [RequiresUnreferencedCode("Json serializer may perform reflection on trimmed types.")] [RequiresDynamicCode("Serializing arbitrary types to json can require creating new generic types or methods, which requires creating code at runtime. This may not work when AOT compiling.")] public NpgsqlDataSourceBuilder EnableDynamicJson(Type[]? jsonbClrTypes = null, Type[]? jsonClrTypes = null) { _internalBuilder.EnableDynamicJson(jsonbClrTypes, jsonClrTypes); return this; } /// /// Sets up mappings for the PostgreSQL record type as a .NET or . /// /// The same builder instance so that multiple calls can be chained. [RequiresUnreferencedCode("The mapping of PostgreSQL records as .NET tuples requires reflection usage which is incompatible with trimming.")] [RequiresDynamicCode("The mapping of PostgreSQL records as .NET tuples requires dynamic code usage which is incompatible with NativeAOT.")] public NpgsqlDataSourceBuilder EnableRecordsAsTuples() { AddTypeInfoResolverFactory(new TupledRecordTypeInfoResolverFactory()); return this; } /// /// Sets up mappings allowing the use of unmapped enum, range and multirange types. /// /// The same builder instance so that multiple calls can be chained. [RequiresUnreferencedCode("The use of unmapped enums, ranges or multiranges requires reflection usage which is incompatible with trimming.")] [RequiresDynamicCode("The use of unmapped enums, ranges or multiranges requires dynamic code usage which is incompatible with NativeAOT.")] public NpgsqlDataSourceBuilder EnableUnmappedTypes() { AddTypeInfoResolverFactory(new UnmappedTypeInfoResolverFactory()); return this; } #region Authentication /// /// When using SSL/TLS, this is a callback that allows customizing how the PostgreSQL-provided certificate is verified. This is an /// advanced API, consider using or instead. /// /// The callback containing custom callback verification logic. /// /// /// Cannot be used in conjunction with , or /// . /// /// /// See . /// /// /// The same builder instance so that multiple calls can be chained. [Obsolete("Use UseSslClientAuthenticationOptionsCallback")] public NpgsqlDataSourceBuilder UseUserCertificateValidationCallback(RemoteCertificateValidationCallback userCertificateValidationCallback) { _internalBuilder.UseUserCertificateValidationCallback(userCertificateValidationCallback); return this; } /// /// Specifies an SSL/TLS certificate which Npgsql will send to PostgreSQL for certificate-based authentication. /// /// The client certificate to be sent to PostgreSQL when opening a connection. /// The same builder instance so that multiple calls can be chained. [Obsolete("Use UseSslClientAuthenticationOptionsCallback")] public NpgsqlDataSourceBuilder UseClientCertificate(X509Certificate? clientCertificate) { _internalBuilder.UseClientCertificate(clientCertificate); return this; } /// /// Specifies a collection of SSL/TLS certificates which Npgsql will send to PostgreSQL for certificate-based authentication. /// /// The client certificate collection to be sent to PostgreSQL when opening a connection. /// The same builder instance so that multiple calls can be chained. [Obsolete("Use UseSslClientAuthenticationOptionsCallback")] public NpgsqlDataSourceBuilder UseClientCertificates(X509CertificateCollection? clientCertificates) { _internalBuilder.UseClientCertificates(clientCertificates); return this; } /// /// When using SSL/TLS, this is a callback that allows customizing SslStream's authentication options. /// /// The callback to customize SslStream's authentication options. /// /// /// See . /// /// /// The same builder instance so that multiple calls can be chained. public NpgsqlDataSourceBuilder UseSslClientAuthenticationOptionsCallback(Action? sslClientAuthenticationOptionsCallback) { _internalBuilder.UseSslClientAuthenticationOptionsCallback(sslClientAuthenticationOptionsCallback); return this; } /// /// Specifies a callback to modify the collection of SSL/TLS client certificates which Npgsql will send to PostgreSQL for /// certificate-based authentication. This is an advanced API, consider using or /// instead. /// /// The callback to modify the client certificate collection. /// /// /// The callback is invoked every time a physical connection is opened, and is therefore suitable for rotating short-lived client /// certificates. Simply make sure the certificate collection argument has the up-to-date certificate(s). /// /// /// The callback's collection argument already includes any client certificates specified via the connection string or environment /// variables. /// /// /// The same builder instance so that multiple calls can be chained. [Obsolete("Use UseSslClientAuthenticationOptionsCallback")] public NpgsqlDataSourceBuilder UseClientCertificatesCallback(Action? clientCertificatesCallback) { _internalBuilder.UseClientCertificatesCallback(clientCertificatesCallback); return this; } /// /// Sets the that will be used validate SSL certificate, received from the server. /// /// The CA certificate. /// The same builder instance so that multiple calls can be chained. public NpgsqlDataSourceBuilder UseRootCertificate(X509Certificate2? rootCertificate) { _internalBuilder.UseRootCertificate(rootCertificate); return this; } /// /// Sets the that will be used validate SSL certificate, received from the server. /// /// The CA certificates. /// The same builder instance so that multiple calls can be chained. public NpgsqlDataSourceBuilder UseRootCertificates(X509Certificate2Collection? rootCertificates) { _internalBuilder.UseRootCertificates(rootCertificates); return this; } /// /// Specifies a callback that will be used to validate SSL certificate, received from the server. /// /// The callback to get CA certificate. /// The same builder instance so that multiple calls can be chained. /// /// This overload, which accepts a callback, is suitable for scenarios where the certificate rotates /// and might change during the lifetime of the application. /// When that's not the case, use the overload which directly accepts the certificate. /// public NpgsqlDataSourceBuilder UseRootCertificateCallback(Func? rootCertificateCallback) { _internalBuilder.UseRootCertificateCallback(rootCertificateCallback); return this; } /// /// Specifies a callback that will be used to validate SSL certificate, received from the server. /// /// The callback to get CA certificates. /// The same builder instance so that multiple calls can be chained. /// /// This overload, which accepts a callback, is suitable for scenarios where the certificate rotates /// and might change during the lifetime of the application. /// When that's not the case, use the overload which directly accepts the certificate. /// /// The same builder instance so that multiple calls can be chained. public NpgsqlDataSourceBuilder UseRootCertificatesCallback(Func? rootCertificateCallback) { _internalBuilder.UseRootCertificatesCallback(rootCertificateCallback); return this; } /// /// Configures a periodic password provider, which is automatically called by the data source at some regular interval. This is the /// recommended way to fetch a rotating access token. /// /// A callback which returns the password to be sent to PostgreSQL. /// How long to cache the password before re-invoking the callback. /// /// If a password refresh attempt fails, it will be re-attempted with this interval. /// This should typically be much lower than . /// /// The same builder instance so that multiple calls can be chained. /// /// /// The provided callback is invoked in a timer, and not when opening connections. It therefore doesn't affect opening time. /// /// /// The provided cancellation token is only triggered when the entire data source is disposed. If you'd like to apply a timeout to the /// token fetching, do so within the provided callback. /// /// public NpgsqlDataSourceBuilder UsePeriodicPasswordProvider( Func>? passwordProvider, TimeSpan successRefreshInterval, TimeSpan failureRefreshInterval) { _internalBuilder.UsePeriodicPasswordProvider(passwordProvider, successRefreshInterval, failureRefreshInterval); return this; } /// /// Configures a password provider, which is called by the data source when opening connections. /// /// /// A callback that may be invoked during which returns the password to be sent to PostgreSQL. /// /// /// A callback that may be invoked during which returns the password to be sent to PostgreSQL. /// /// The same builder instance so that multiple calls can be chained. /// /// /// The provided callback is invoked when opening connections. Therefore its important the callback internally depends on cached /// data or returns quickly otherwise. Any unnecessary delay will affect connection opening time. /// /// public NpgsqlDataSourceBuilder UsePasswordProvider( Func? passwordProvider, Func>? passwordProviderAsync) { _internalBuilder.UsePasswordProvider(passwordProvider, passwordProviderAsync); return this; } /// /// When using Kerberos, this is a callback that allows customizing default settings for Kerberos authentication. /// /// The callback containing logic to customize Kerberos authentication settings. /// /// /// See . /// /// /// The same builder instance so that multiple calls can be chained. public NpgsqlDataSourceBuilder UseNegotiateOptionsCallback(Action? negotiateOptionsCallback) { _internalBuilder.UseNegotiateOptionsCallback(negotiateOptionsCallback); return this; } #endregion Authentication #region Type mapping /// void INpgsqlTypeMapper.AddDbTypeResolverFactory(DbTypeResolverFactory factory) => ((INpgsqlTypeMapper)_internalBuilder).AddDbTypeResolverFactory(factory); /// [Experimental(NpgsqlDiagnostics.ConvertersExperimental)] public void AddTypeInfoResolverFactory(PgTypeInfoResolverFactory factory) => _internalBuilder.AddTypeInfoResolverFactory(factory); /// void INpgsqlTypeMapper.Reset() => ((INpgsqlTypeMapper)_internalBuilder).Reset(); /// /// Maps a CLR enum to a PostgreSQL enum type. /// /// /// CLR enum labels are mapped by name to PostgreSQL enum labels. /// The translation strategy can be controlled by the parameter, /// which defaults to . /// You can also use the on your enum fields to manually specify a PostgreSQL enum label. /// If there is a discrepancy between the .NET and database labels while an enum is read or written, /// an exception will be raised. /// /// /// A PostgreSQL type name for the corresponding enum type in the database. /// If null, the name translator given in will be used. /// /// /// A component which will be used to translate CLR names (e.g. SomeClass) into database names (e.g. some_class). /// Defaults to . /// /// The .NET enum type to be mapped public NpgsqlDataSourceBuilder MapEnum<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] TEnum>(string? pgName = null, INpgsqlNameTranslator? nameTranslator = null) where TEnum : struct, Enum { _internalBuilder.MapEnum(pgName, nameTranslator); return this; } /// public bool UnmapEnum<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] TEnum>(string? pgName = null, INpgsqlNameTranslator? nameTranslator = null) where TEnum : struct, Enum => _internalBuilder.UnmapEnum(pgName, nameTranslator); /// /// Maps a CLR enum to a PostgreSQL enum type. /// /// /// CLR enum labels are mapped by name to PostgreSQL enum labels. /// The translation strategy can be controlled by the parameter, /// which defaults to . /// You can also use the on your enum fields to manually specify a PostgreSQL enum label. /// If there is a discrepancy between the .NET and database labels while an enum is read or written, /// an exception will be raised. /// /// The .NET enum type to be mapped /// /// A PostgreSQL type name for the corresponding enum type in the database. /// If null, the name translator given in will be used. /// /// /// A component which will be used to translate CLR names (e.g. SomeClass) into database names (e.g. some_class). /// Defaults to . /// [RequiresDynamicCode("Calling MapEnum with a Type can require creating new generic types or methods. This may not work when AOT compiling.")] public NpgsqlDataSourceBuilder MapEnum([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] Type clrType, string? pgName = null, INpgsqlNameTranslator? nameTranslator = null) { _internalBuilder.MapEnum(clrType, pgName, nameTranslator); return this; } /// public bool UnmapEnum([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] Type clrType, string? pgName = null, INpgsqlNameTranslator? nameTranslator = null) => _internalBuilder.UnmapEnum(clrType, pgName, nameTranslator); /// /// Maps a CLR type to a PostgreSQL composite type. /// /// /// CLR fields and properties by string to PostgreSQL names. /// The translation strategy can be controlled by the parameter, /// which defaults to . /// You can also use the on your members to manually specify a PostgreSQL name. /// If there is a discrepancy between the .NET type and database type while a composite is read or written, /// an exception will be raised. /// /// /// A PostgreSQL type name for the corresponding composite type in the database. /// If null, the name translator given in will be used. /// /// /// A component which will be used to translate CLR names (e.g. SomeClass) into database names (e.g. some_class). /// Defaults to . /// /// The .NET type to be mapped [RequiresDynamicCode("Mapping composite types involves serializing arbitrary types which can require creating new generic types or methods. This is currently unsupported with NativeAOT, vote on issue #5303 if this is important to you.")] public NpgsqlDataSourceBuilder MapComposite<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.PublicFields)] T>( string? pgName = null, INpgsqlNameTranslator? nameTranslator = null) { _internalBuilder.MapComposite(typeof(T), pgName, nameTranslator); return this; } /// [RequiresDynamicCode("Mapping composite types involves serializing arbitrary types which can require creating new generic types or methods. This is currently unsupported with NativeAOT, vote on issue #5303 if this is important to you.")] public bool UnmapComposite<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.PublicFields)] T>( string? pgName = null, INpgsqlNameTranslator? nameTranslator = null) => _internalBuilder.UnmapComposite(typeof(T), pgName, nameTranslator); /// /// Maps a CLR type to a composite type. /// /// /// Maps CLR fields and properties by string to PostgreSQL names. /// The translation strategy can be controlled by the parameter, /// which defaults to . /// If there is a discrepancy between the .NET type and database type while a composite is read or written, /// an exception will be raised. /// /// The .NET type to be mapped. /// /// A PostgreSQL type name for the corresponding composite type in the database. /// If null, the name translator given in will be used. /// /// /// A component which will be used to translate CLR names (e.g. SomeClass) into database names (e.g. some_class). /// Defaults to . /// [RequiresDynamicCode("Mapping composite types involves serializing arbitrary types which can require creating new generic types or methods. This is currently unsupported with NativeAOT, vote on issue #5303 if this is important to you.")] public NpgsqlDataSourceBuilder MapComposite([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.PublicFields)] Type clrType, string? pgName = null, INpgsqlNameTranslator? nameTranslator = null) { _internalBuilder.MapComposite(clrType, pgName, nameTranslator); return this; } /// [RequiresDynamicCode("Mapping composite types involves serializing arbitrary types which can require creating new generic types or methods. This is currently unsupported with NativeAOT, vote on issue #5303 if this is important to you.")] public bool UnmapComposite([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.PublicFields)] Type clrType, string? pgName = null, INpgsqlNameTranslator? nameTranslator = null) => _internalBuilder.UnmapComposite(clrType, pgName, nameTranslator); #endregion Type mapping /// /// Register a connection initializer, which allows executing arbitrary commands when a physical database connection is first opened. /// /// /// A synchronous connection initialization lambda, which will be called from when a new physical /// connection is opened. /// /// /// An asynchronous connection initialization lambda, which will be called from /// when a new physical connection is opened. /// /// /// If an initializer is registered, both sync and async versions must be provided. If you do not use sync APIs in your code, simply /// throw , which would also catch accidental cases of sync opening. /// /// /// Take care that the setting you apply in the initializer does not get reverted when the connection is returned to the pool, since /// Npgsql sends DISCARD ALL by default. The option can be used to /// turn this off. /// /// The same builder instance so that multiple calls can be chained. public NpgsqlDataSourceBuilder UsePhysicalConnectionInitializer( Action? connectionInitializer, Func? connectionInitializerAsync) { _internalBuilder.UsePhysicalConnectionInitializer(connectionInitializer, connectionInitializerAsync); return this; } /// /// Builds and returns an which is ready for use. /// public NpgsqlDataSource Build() => _internalBuilder.Build(); /// /// Builds and returns a which is ready for use for load-balancing and failover scenarios. /// public NpgsqlMultiHostDataSource BuildMultiHost() => _internalBuilder.BuildMultiHost(); // Used in testing. internal (NpgsqlConnectionStringBuilder, NpgsqlDataSourceConfiguration) PrepareConfiguration() => _internalBuilder.PrepareConfiguration(); INpgsqlTypeMapper INpgsqlTypeMapper.ConfigureJsonOptions(JsonSerializerOptions serializerOptions) => ConfigureJsonOptions(serializerOptions); [RequiresUnreferencedCode("Json serializer may perform reflection on trimmed types.")] [RequiresDynamicCode( "Serializing arbitrary types to json can require creating new generic types or methods, which requires creating code at runtime. This may not work when AOT compiling.")] INpgsqlTypeMapper INpgsqlTypeMapper.EnableDynamicJson(Type[]? jsonbClrTypes, Type[]? jsonClrTypes) => EnableDynamicJson(jsonbClrTypes, jsonClrTypes); [RequiresUnreferencedCode( "The mapping of PostgreSQL records as .NET tuples requires reflection usage which is incompatible with trimming.")] [RequiresDynamicCode( "The mapping of PostgreSQL records as .NET tuples requires dynamic code usage which is incompatible with NativeAOT.")] INpgsqlTypeMapper INpgsqlTypeMapper.EnableRecordsAsTuples() => EnableRecordsAsTuples(); [RequiresUnreferencedCode( "The use of unmapped enums, ranges or multiranges requires reflection usage which is incompatible with trimming.")] [RequiresDynamicCode( "The use of unmapped enums, ranges or multiranges requires dynamic code usage which is incompatible with NativeAOT.")] INpgsqlTypeMapper INpgsqlTypeMapper.EnableUnmappedTypes() => EnableUnmappedTypes(); /// INpgsqlTypeMapper INpgsqlTypeMapper.MapEnum<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] TEnum>(string? pgName, INpgsqlNameTranslator? nameTranslator) { _internalBuilder.MapEnum(pgName, nameTranslator); return this; } /// [RequiresDynamicCode("Calling MapEnum with a Type can require creating new generic types or methods. This may not work when AOT compiling.")] INpgsqlTypeMapper INpgsqlTypeMapper.MapEnum([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] Type clrType, string? pgName, INpgsqlNameTranslator? nameTranslator) { _internalBuilder.MapEnum(clrType, pgName, nameTranslator); return this; } /// [RequiresDynamicCode("Mapping composite types involves serializing arbitrary types which can require creating new generic types or methods. This is currently unsupported with NativeAOT, vote on issue #5303 if this is important to you.")] INpgsqlTypeMapper INpgsqlTypeMapper.MapComposite<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.PublicFields)] T>( string? pgName, INpgsqlNameTranslator? nameTranslator) { _internalBuilder.MapComposite(typeof(T), pgName, nameTranslator); return this; } /// [RequiresDynamicCode("Mapping composite types involves serializing arbitrary types which can require creating new generic types or methods. This is currently unsupported with NativeAOT, vote on issue #5303 if this is important to you.")] INpgsqlTypeMapper INpgsqlTypeMapper.MapComposite([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.PublicFields)] Type clrType, string? pgName, INpgsqlNameTranslator? nameTranslator) { _internalBuilder.MapComposite(clrType, pgName, nameTranslator); return this; } }
X Tutup