Ejemplo n.º 1
0
        public void InsertSync <T>(T[] items, DbConnection con, DbTransaction tx = null)
        {
            var table          = TypeToTableEntry <T> .DefaultTable;
            var q              = new BaseInsertQuery(table).WithValues(items.Select((item, i) => TypeToTableEntry <T> .ToValues(item, table, i)).ToArray());
            var returningParts = TypeToTableEntry <T> .Returning(items[0], table);

            if (returningParts != null)
            {
                q = q.Returning(returningParts);
                var ids = q.ScalarListSync <int>(con, tx, items.Length == 1);

                if (ids.Count != items.Length)
                {
                    throw new InvalidOperationException();
                }

                for (int i = 0; i < items.Length; i++)
                {
                    TypeToTableEntry <T> .ApplyReturning(items[i], ids[i]);
                }
            }
            else
            {
                q.ExecuteSync(con, tx, items.Length == 1);
            }
        }
Ejemplo n.º 2
0
        public static void RegisterTypeToTable <T, TTable>() where TTable : Table
        {
            var c = typeof(TTable).GetConstructor(
                new[] {
                typeof(string)
            });

            if (c == null)
            {
                throw new ArgumentException($"Table type `{typeof(TTable).FullName}` does not have a constructor that takes a string (the alias)");
            }

            var a = Expression.Parameter(typeof(string));

            TypeToTableEntry <T> .TableConstructor = Expression.Lambda <Func <string, Table> >(Expression.Convert(Expression.New(c, a), typeof(Table)), a).Compile();
            TypeToTableEntry <T> .DefaultTable     = TypeToTableEntry <T> .TableConstructor("");

            var pk       = typeof(TTable).GetTypeInfo().GetCustomAttribute <PrimaryKeyAttribute>();
            var tableArg = Expression.Parameter(typeof(Table));
            var objArg   = Expression.Parameter(typeof(object));

            if (pk != null)
            {
                var baseEqMethod = typeof(Field).GetMethods().First(m => m.Name == "EqV" && m.IsGenericMethod);

                var l = Expression.Lambda <Func <object, Table, IBooleanPart[]> >(
                    Expression.NewArrayInit(typeof(IBooleanPart),
                                            pk.Fields.Select(f => typeof(TTable).GetField(f)).Select(fi => {
                    var originalField = typeof(T).GetField(fi.Name);

                    if (originalField == null)
                    {
                        var prop = typeof(T).GetProperty(fi.Name);

                        if (prop == null)
                        {
                            throw new ArgumentException($"Type `{typeof(T).FullName}` does not have a member of name `{fi.Name}`");
                        }

                        return(Expression.Call(Expression.Field(Expression.Convert(tableArg, typeof(TTable)), fi),
                                               baseEqMethod.MakeGenericMethod(prop.PropertyType), Expression.Property(Expression.Convert(objArg, typeof(T)), prop), Expression.Constant(null, typeof(string))));
                    }
                    return(Expression.Call(Expression.Field(Expression.Convert(tableArg, typeof(TTable)), fi), baseEqMethod.MakeGenericMethod(originalField.FieldType), Expression.Field(Expression.Convert(objArg, typeof(T)), originalField), Expression.Constant(null, typeof(string))));
                })
                                            ), objArg, tableArg);
                TypeToTableEntry <T> .GetDefaultConditions = l.Compile();
            }

            var vcVar        = Expression.Variable(typeof(ValuesCollection));
            var addMethod    = typeof(ValuesCollection).GetMethod("Add");
            var setVMethod   = typeof(Field).GetMethod(nameof(Field.SetV));
            var tableFields  = typeof(TTable).GetFields().Where(f => f.Name != "TableName" && f.Name != "TableSchema" && f.Name != "TableAlias").ToList();
            var tableProps   = typeof(TTable).GetProperties();
            var nArg         = Expression.Parameter(typeof(int));
            var concatMethod = typeof(string).GetMethod("Concat", new[] { typeof(string), typeof(string) });
            var intToStr     = typeof(int).GetMethod("ToString", Type.EmptyTypes);

            var memberThings = tableFields.Select(f => {
                MemberExpression memberExpression = null;
                Type targetType;
                MethodCallExpression setMethod;
                MemberExpression tableFieldExpr = Expression.Field(Expression.Convert(tableArg, typeof(TTable)), f);

                var paraNameExpr = Expression.Call(null, concatMethod, Expression.Constant(f.Name), Expression.Call(nArg, intToStr));

                var originalField = typeof(T).GetField(f.Name);
                if (originalField == null)
                {
                    var prop = typeof(T).GetProperty(f.Name);

                    if (prop == null)
                    {
                        throw new ArgumentException($"Type `{typeof(T).FullName}` does not have a member of name `{f.Name}`");
                    }

                    memberExpression = Expression.Property(Expression.Convert(objArg, typeof(T)), prop);
                    targetType       = prop.PropertyType;

                    setMethod = Expression.Call(tableFieldExpr, setVMethod.MakeGenericMethod(prop.PropertyType), Expression.Property(Expression.Convert(objArg, typeof(T)), prop), paraNameExpr);
                }
                else
                {
                    memberExpression = Expression.Field(Expression.Convert(objArg, typeof(T)), originalField);

                    targetType = originalField.FieldType;
                    setMethod  = Expression.Call(tableFieldExpr, setVMethod.MakeGenericMethod(originalField.FieldType), Expression.Field(Expression.Convert(objArg, typeof(T)), originalField), paraNameExpr);
                }

                return(memberExpression: memberExpression, targetType: targetType, memberName: f.Name, setMethod: setMethod, tableFieldExpression: tableFieldExpr);
            }).Concat(tableProps.Select(
                          p => {
                MemberExpression memberExpression = null;
                Type targetType;
                MethodCallExpression setMethod;
                MemberExpression tableFieldExpr = Expression.Property(Expression.Convert(tableArg, typeof(TTable)), p);;

                var paraNameExpr  = Expression.Call(null, concatMethod, Expression.Constant(p.Name), Expression.Call(null, intToStr, nArg));
                var originalField = typeof(T).GetField(p.Name);
                if (originalField == null)
                {
                    var prop = typeof(T).GetProperty(p.Name);

                    if (prop == null)
                    {
                        throw new ArgumentException($"Type `{typeof(T).FullName}` does not have a member of name `{p.Name}`");
                    }

                    memberExpression = Expression.Property(Expression.Convert(objArg, typeof(T)), prop);
                    targetType       = prop.PropertyType;
                    setMethod        = Expression.Call(Expression.Property(Expression.Convert(tableArg, typeof(TTable)), p),
                                                       setVMethod.MakeGenericMethod(prop.PropertyType), Expression.Property(Expression.Convert(objArg, typeof(T)), prop), paraNameExpr);
                }
                else
                {
                    memberExpression = Expression.Field(Expression.Convert(objArg, typeof(T)), originalField);
                    targetType       = originalField.FieldType;
                    setMethod        = Expression.Call(tableFieldExpr, setVMethod.MakeGenericMethod(originalField.FieldType), Expression.Field(Expression.Convert(objArg, typeof(T)), originalField), paraNameExpr);
                }

                return(memberExpression: memberExpression, targetType: targetType, memberName: p.Name, setMethod: setMethod, tableFieldExpression: tableFieldExpr);
            })).ToList();

            var blockExpressions = new List <Expression> {
                Expression.Assign(vcVar, Expression.New(typeof(ValuesCollection)))
            };

            foreach (var thing in memberThings)
            {
                var setExpr = Expression.Assign(vcVar, Expression.Call(vcVar, addMethod,
                                                                       Expression.NewArrayInit(typeof(SetFieldPart), thing.Item4)
                                                                       ));

                if (pk != null && pk.Fields.Length == 1 && pk.Fields[0] == thing.memberName && pk.SingleKeyIsAutoincrement)
                {
                    blockExpressions.Add(
                        Expression.IfThen(Expression.Not(Expression.Equal(Expression.Default(thing.targetType), thing.memberExpression)), setExpr)
                        );
                }
                else
                {
                    blockExpressions.Add(setExpr);
                }
            }

            blockExpressions.Add(vcVar);

            TypeToTableEntry <T> .ToValues = Expression.Lambda <Func <object, Table, int, ValuesCollection> >(
                Expression.Block(
                    new[] {
                vcVar
            },
                    blockExpressions.ToArray()),
                objArg,
                tableArg,
                nArg).Compile();


            if (pk != null && pk.Fields.Length == 1 && pk.SingleKeyIsAutoincrement)
            {
                var mt = memberThings.Single(x => x.memberName == pk.Fields[0]);
                if (mt.Item2 == typeof(int) || mt.Item2 == typeof(long))
                {
                    var partArr = Expression.Variable(typeof(IPart[]));
                    TypeToTableEntry <T> .Returning = Expression.Lambda <Func <object, Table, IPart[]> >(
                        Expression.Block(
                            new [] { partArr },
                            Expression.IfThen(Expression.Equal(Expression.Default(mt.Item2), mt.Item1),
                                              Expression.Assign(partArr, Expression.NewArrayInit(typeof(IPart), mt.Item5))),
                            partArr),
                        new [] { objArg, tableArg }
                        ).Compile();

                    var obj2Arg = Expression.Parameter(typeof(object));

                    if (mt.Item2 == typeof(long))
                    {
                        var conversionMethod = typeof(Convert).GetMethod(
                            "ToInt64",
                            new Type[] {
                            typeof(object)
                        });

                        TypeToTableEntry <T> .ApplyReturning = Expression.Lambda <Action <object, object> >(
                            Expression.Assign(mt.Item1, Expression.Call(conversionMethod, obj2Arg)),
                            new[] {
                            objArg,
                            obj2Arg
                        }
                            ).Compile();
                    }
                    else
                    {
                        TypeToTableEntry <T> .ApplyReturning = Expression.Lambda <Action <object, object> >(
                            Expression.Assign(mt.Item1, Expression.Convert(obj2Arg, mt.Item2)),
                            new[] {
                            objArg,
                            obj2Arg
                        }
                            ).Compile();
                    }
                }
            }
        }