Exemplo n.º 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;
        }
    }
Exemplo n.º 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.TryResolveByOID(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);
    }