Пример #1
0
        void Initialize()
        {
            if (_memberHandlers is null)
            {
                InitializeCore();
            }

            void InitializeCore()
            {
                var pgType = (PostgresCompositeType)PostgresType;

                _memberHandlers     = CreateMemberHandlers(pgType, _typeMapper, _nameTranslator);
                _constructorHandler = CreateConstructorHandler(pgType, _typeMapper, _nameTranslator);
                _constructor        = _constructorHandler is null
                    ? Expression
                                      .Lambda <Func <T> >(Expression.New(typeof(T)))
                                      .Compile()
                    : null;
            }
        }
Пример #2
0
        static CompositeConstructorHandler <T>?CreateConstructorHandler(PostgresCompositeType pgType, ConnectorTypeMapper typeMapper, INpgsqlNameTranslator nameTranslator)
        {
            var pgFields = pgType.Fields;
            var clrType  = typeof(T);

            ConstructorInfo?clrDefaultConstructor = null;

            foreach (var clrConstructor in clrType.GetConstructors())
            {
                var clrParameters = clrConstructor.GetParameters();
                if (clrParameters.Length != pgFields.Count)
                {
                    if (clrParameters.Length == 0)
                    {
                        clrDefaultConstructor = clrConstructor;
                    }

                    continue;
                }

                var clrParameterHandlerCount = 0;
                var clrParametersMapped      = new ParameterInfo[pgFields.Count];

                foreach (var clrParameter in clrParameters)
                {
                    var attr = clrParameter.GetCustomAttribute <PgNameAttribute>();
                    var name = attr?.PgName ?? (clrParameter.Name is string clrName ? nameTranslator.TranslateMemberName(clrName) : null);
                    if (name is null)
                    {
                        break;
                    }

                    for (var pgFieldIndex = pgFields.Count - 1; pgFieldIndex >= 0; --pgFieldIndex)
                    {
                        var pgField = pgFields[pgFieldIndex];
                        if (pgField.Name != name)
                        {
                            continue;
                        }

                        if (clrParametersMapped[pgFieldIndex] != null)
                        {
                            throw new AmbiguousMatchException($"Multiple constructor parameters are mapped to the '{pgField.Name}' field.");
                        }

                        clrParameterHandlerCount++;
                        clrParametersMapped[pgFieldIndex] = clrParameter;

                        break;
                    }
                }

                if (clrParameterHandlerCount < pgFields.Count)
                {
                    continue;
                }

                var clrParameterHandlers = new CompositeParameterHandler[pgFields.Count];
                for (var pgFieldIndex = 0; pgFieldIndex < pgFields.Count; ++pgFieldIndex)
                {
                    var pgField = pgFields[pgFieldIndex];

                    if (!typeMapper.TryGetByOID(pgField.Type.OID, out var handler))
                    {
                        throw new NpgsqlException($"PostgreSQL composite type {pgType.DisplayName} has field {pgField.Type.DisplayName} with an unknown type (OID = {pgField.Type.OID}).");
                    }

                    var clrParameter            = clrParametersMapped[pgFieldIndex];
                    var clrParameterHandlerType = typeof(CompositeParameterHandler <>)
                                                  .MakeGenericType(clrParameter.ParameterType);

                    clrParameterHandlers[pgFieldIndex] = (CompositeParameterHandler)Activator.CreateInstance(
                        clrParameterHandlerType,
                        BindingFlags.Instance | BindingFlags.Public,
                        binder: null,
                        args: new object[] { handler, clrParameter },
                        culture: null) !;
                }

                return(CompositeConstructorHandler <T> .Create(pgType, clrConstructor, clrParameterHandlers));
            }

            if (clrDefaultConstructor is null && !clrType.IsValueType)
            {
                throw new InvalidOperationException($"No parameterless constructor defined for type '{clrType}'.");
            }

            return(null);
        }