public CodeTypeReference GetReturnType(PrimitiveRepresentation rep, FieldInfo fi)
        {
            switch (rep)
            {
            case PrimitiveRepresentation.Boxed:
                return(new CodeTypeReference(typeof(object)));

            case PrimitiveRepresentation.SqlType:
                Type t = fi.GetNullableFieldHandler().GetSqlType();
                if (t == null)
                {
                    return(new CodeTypeReference(fi.GetNullableFieldHandler().GetFieldType()));
                }
                else
                {
                    return(new CodeTypeReference(t));
                }

            case PrimitiveRepresentation.RawWithIsNull:
            case PrimitiveRepresentation.Raw:
                return(new CodeTypeReference(fi.GetNullableFieldHandler().GetFieldType()));

            case PrimitiveRepresentation.Nullable:
                return(new CodeTypeReference(fi.GetNullableFieldHandler().GetNullableType()));

            default:
                throw new NotImplementedException("Unknown PrimitiveRepresentation: " + rep);
            }
        }
        public CodeTypeReference GetReturnType(PrimitiveRepresentation rep, FieldInfo fi)
        {
            switch (rep)
            {
                case PrimitiveRepresentation.Boxed:
                    return new CodeTypeReference(typeof(object));

                case PrimitiveRepresentation.SqlType:
                    Type t = fi.GetNullableFieldHandler().GetSqlType();
                    if (t == null)
                        return new CodeTypeReference(fi.GetNullableFieldHandler().GetFieldType());
                    else
                        return new CodeTypeReference(t);

                case PrimitiveRepresentation.RawWithIsNull:
                case PrimitiveRepresentation.Raw:
                    return new CodeTypeReference(fi.GetNullableFieldHandler().GetFieldType());

                case PrimitiveRepresentation.Nullable:
                    return new CodeTypeReference(fi.GetNullableFieldHandler().GetNullableType());

                default:
                    throw new NotImplementedException("Unknown PrimitiveRepresentation: " + rep);
            }
        }
        public void GenerateProperties(CodeTypeDeclaration ctd, ClassInfo ci)
        {
            CodeMemberProperty prop;

            foreach (FieldInfo fi in classInfo.LocalFields)
            {
                if (fi.References != null)
                {
                    continue;
                }

                if (fi.IsNullable)
                {
                    if (options.NullableRepresentation == PrimitiveRepresentation.RawWithIsNull)
                    {
                        ctd.Members.Add(_IsNull(fi));
                        if (!ci.ReadOnly)
                        {
                            ctd.Members.Add(_SetNull(fi));
                        }
                    }
                }
                else
                {
                    if (options.NotNullRepresentation == PrimitiveRepresentation.RawWithIsNull)
                    {
                        if (!ci.ReadOnly)
                        {
                            // if it's read-only, not-null means not-null and there's no
                            // exception
                            ctd.Members.Add(_IsNull(fi));
                        }
                    }
                }
            }

            int primaryKeyComponentNumber = 0;

            foreach (FieldInfo fi in classInfo.LocalFields)
            {
                PrimitiveRepresentation actualNullableRepresentation = options.NullableRepresentation;
                PrimitiveRepresentation actualNotNullRepresentation  = options.NotNullRepresentation;

                if (fi.GetNullableFieldHandler().GetSqlType() == null)
                {
                    if (actualNotNullRepresentation == PrimitiveRepresentation.SqlType)
                    {
                        actualNotNullRepresentation = PrimitiveRepresentation.Raw;
                    }

                    if (actualNullableRepresentation == PrimitiveRepresentation.SqlType)
                    {
                        actualNullableRepresentation = PrimitiveRepresentation.Raw;
                    }
                }

                CodeTypeReference returnType;

                //if (fi.Name == ci.PrimaryKeyFieldName)
                //{
                //  returnType = GetReturnType(PrimitiveRepresentation.Raw, fi.DataType);
                //}
                //else
                if (fi.References != null)
                {
                    returnType = new CodeTypeReference(fi.References);
                }
                else if (fi.IsNullable)
                {
                    returnType = GetReturnType(actualNullableRepresentation, fi);
                }
                else
                {
                    returnType = GetReturnType(actualNotNullRepresentation, fi);
                }

                prop            = new CodeMemberProperty();
                prop.Name       = fi.Name;
                prop.Attributes = MemberAttributes.Final | MemberAttributes.Public;
                prop.Type       = returnType;
                //prop.GetStatements.Add(new CodeMethodReturnStatement(new CodeFieldReferenceExpression(null, "_FieldNames")));
                if (fi.Description != null)
                {
                    prop.Comments.Add(new CodeCommentStatement("<summary>", true));
                    prop.Comments.Add(new CodeCommentStatement(fi.Description, true));
                    prop.Comments.Add(new CodeCommentStatement("</summary>", true));
                }
                ctd.Members.Add(prop);

                if (fi.Size != -1)
                {
                    CodeAttributeDeclaration cad = new CodeAttributeDeclaration("Sooda.SoodaFieldSizeAttribute");
                    cad.Arguments.Add(new CodeAttributeArgument(new CodePrimitiveExpression(fi.Size)));
                    prop.CustomAttributes.Add(cad);
                }

                if (fi.IsPrimaryKey)
                {
                    CodeExpression getPrimaryKeyValue = new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), "GetPrimaryKeyValue");

                    if (classInfo.GetPrimaryKeyFields().Length > 1)
                    {
                        getPrimaryKeyValue = new CodeMethodInvokeExpression(
                            new CodeTypeReferenceExpression(typeof(SoodaTuple)), "GetValue", getPrimaryKeyValue, new CodePrimitiveExpression(primaryKeyComponentNumber));
                    }

                    if (fi.References != null)
                    {
                        prop.GetStatements.Add(
                            new CodeMethodReturnStatement(
                                new CodeMethodInvokeExpression(
                                    LoaderClass(fi.ReferencedClass),
                                    "GetRef",
                                    GetTransaction(),
                                    new CodeCastExpression(
                                        GetReturnType(actualNotNullRepresentation, fi),
                                        getPrimaryKeyValue
                                        ))));
                    }
                    else
                    {
                        prop.GetStatements.Add(
                            new CodeMethodReturnStatement(
                                new CodeCastExpression(
                                    prop.Type,
                                    getPrimaryKeyValue
                                    )));
                    }

                    if (!classInfo.ReadOnly && !fi.ReadOnly)
                    {
                        if (classInfo.GetPrimaryKeyFields().Length == 1)
                        {
                            prop.SetStatements.Add(
                                new CodeExpressionStatement(
                                    new CodeMethodInvokeExpression(
                                        new CodeThisReferenceExpression(), "SetPrimaryKeyValue",
                                        new CodePropertySetValueReferenceExpression())));
                        }
                        else
                        {
                            CodeExpression plainValue = new CodePropertySetValueReferenceExpression();
                            if (fi.References != null)
                            {
                                plainValue = new CodeMethodInvokeExpression(plainValue, "GetPrimaryKeyValue");
                            }
                            prop.SetStatements.Add(
                                new CodeExpressionStatement(
                                    new CodeMethodInvokeExpression(
                                        new CodeThisReferenceExpression(), "SetPrimaryKeySubValue",
                                        plainValue,
                                        new CodePrimitiveExpression(primaryKeyComponentNumber),
                                        new CodePrimitiveExpression(classInfo.GetPrimaryKeyFields().Length))));
                        }
                    }
                    primaryKeyComponentNumber++;
                    continue;
                }

                if (options.NullPropagation && (fi.References != null || fi.IsNullable) && actualNullableRepresentation != PrimitiveRepresentation.Raw)
                {
                    CodeExpression retVal = new CodePrimitiveExpression(null);

                    if (fi.References == null && actualNullableRepresentation == PrimitiveRepresentation.SqlType)
                    {
                        retVal = new CodePropertyReferenceExpression(
                            new CodeTypeReferenceExpression(fi.GetNullableFieldHandler().GetSqlType()), "Null");
                    }

                    prop.GetStatements.Add(
                        new CodeConditionStatement(
                            new CodeBinaryOperatorExpression(
                                new CodeThisReferenceExpression(),
                                CodeBinaryOperatorType.IdentityEquality,
                                new CodePrimitiveExpression(null)),
                            new CodeStatement[]
                    {
                        new CodeMethodReturnStatement(retVal)
                    },
                            new CodeStatement[]
                    {
                    }));
                }

                if (fi.References != null)
                {
                    // reference field getter
                    //
                    CodeExpression pk = new CodeVariableReferenceExpression("pk");
                    Type           pkType;
                    CodeExpression isFieldNotNull;
                    CodeExpression getRef;
                    if (fi.ParentClass.GetDataSource().EnableDynamicFields)
                    {
                        pkType         = typeof(object);
                        isFieldNotNull = new CodeBinaryOperatorExpression(
                            pk,
                            CodeBinaryOperatorType.IdentityInequality,
                            new CodePrimitiveExpression(null));
                        getRef = new CodeMethodInvokeExpression(
                            new CodeTypeReferenceExpression(typeof(SoodaObject)),
                            "GetRefHelper",
                            GetTransaction(),
                            Factory(fi.References),
                            pk);
                    }
                    else
                    {
                        pkType         = fi.GetNullableFieldHandler().GetSqlType();
                        isFieldNotNull = new CodeBinaryOperatorExpression(
                            new CodePropertyReferenceExpression(pk, "IsNull"),
                            CodeBinaryOperatorType.ValueEquality,
                            new CodePrimitiveExpression(false));
                        getRef = new CodeMethodInvokeExpression(
                            LoaderClass(fi.ReferencedClass),
                            "GetRef",
                            GetTransaction(),
                            new CodePropertyReferenceExpression(pk, "Value"));
                    }
                    prop.GetStatements.Add(
                        new CodeConditionStatement(
                            new CodeBinaryOperatorExpression(
                                RefCacheExpression(ci, fi),
                                CodeBinaryOperatorType.IdentityEquality,
                                new CodePrimitiveExpression(null)),
                            new CodeStatement[]
                    {
                        new CodeVariableDeclarationStatement(pkType, "pk", GetFieldValueForRead(fi)),
                        new CodeConditionStatement(
                            isFieldNotNull,
                            new CodeStatement[]
                        {
                            new CodeAssignStatement(
                                RefCacheExpression(ci, fi),
                                getRef)
                        })
                    }
                            ));


                    prop.GetStatements.Add(
                        new CodeMethodReturnStatement(
                            new CodeCastExpression(returnType,
                                                   RefCacheExpression(ci, fi))));

                    // reference field setter
                    if (!classInfo.ReadOnly && !fi.ReadOnly)
                    {
                        prop.SetStatements.Add(
                            new CodeExpressionStatement(

                                new CodeMethodInvokeExpression(
                                    new CodeTypeReferenceExpression(typeof(Sooda.ObjectMapper.SoodaObjectImpl)), "SetRefFieldValue",

                                    // parameters
                                    new CodeThisReferenceExpression(),
                                    new CodePrimitiveExpression(fi.Table.OrdinalInClass),
                                    new CodePrimitiveExpression(fi.Name),
                                    new CodePrimitiveExpression(fi.ClassUnifiedOrdinal),
                                    new CodePropertySetValueReferenceExpression(),
                                    RefCacheArray(),
                                    new CodePrimitiveExpression(GetFieldRefCacheIndex(ci, fi)),
                                    Factory(returnType.BaseType)
                                    )));
                    }
                }
                else
                {
                    // plain field getter

                    CodeExpression fieldValue = GetFieldValueForRead(fi);
                    if (fi.ParentClass.GetDataSource().EnableDynamicFields)
                    {
                        switch (fi.IsNullable ? actualNullableRepresentation : actualNotNullRepresentation)
                        {
                        case PrimitiveRepresentation.Boxed:
                            break;

                        case PrimitiveRepresentation.SqlType:
                        case PrimitiveRepresentation.RawWithIsNull:
                        case PrimitiveRepresentation.Raw:
                            fieldValue = new CodeCastExpression(new CodeTypeReference(fi.GetNullableFieldHandler().GetFieldType()), fieldValue);
                            break;

                        case PrimitiveRepresentation.Nullable:
                            fieldValue = new CodeCastExpression(new CodeTypeReference(fi.GetNullableFieldHandler().GetNullableType()), fieldValue);
                            break;

                        default:
                            throw new NotImplementedException("Unknown PrimitiveRepresentation");
                        }
                    }
                    prop.GetStatements.Add(new CodeMethodReturnStatement(fieldValue));

                    if (!classInfo.ReadOnly && !fi.ReadOnly)
                    {
                        // plain field setter

                        CodeExpression beforeDelegate = new CodePrimitiveExpression(null);
                        CodeExpression afterDelegate  = new CodePrimitiveExpression(null);

                        if (classInfo.Triggers)
                        {
                            beforeDelegate = new CodeDelegateCreateExpression(new CodeTypeReference(typeof(SoodaFieldUpdateDelegate)),
                                                                              new CodeThisReferenceExpression(), "BeforeFieldUpdate_" + fi.Name);
                            afterDelegate = new CodeDelegateCreateExpression(new CodeTypeReference(typeof(SoodaFieldUpdateDelegate)),
                                                                             new CodeThisReferenceExpression(), "AfterFieldUpdate_" + fi.Name);
                        }

                        prop.SetStatements.Add(
                            new CodeExpressionStatement(
                                new CodeMethodInvokeExpression(
                                    new CodeTypeReferenceExpression(typeof(Sooda.ObjectMapper.SoodaObjectImpl)), "SetPlainFieldValue",

                                    // parameters
                                    new CodeThisReferenceExpression(),
                                    new CodePrimitiveExpression(fi.Table.OrdinalInClass),
                                    new CodePrimitiveExpression(fi.Name),
                                    new CodePrimitiveExpression(fi.ClassUnifiedOrdinal),
                                    Box(new CodePropertySetValueReferenceExpression()),
                                    beforeDelegate,
                                    afterDelegate
                                    )));
                    }
                }
            }


            if (classInfo.Collections1toN != null)
            {
                foreach (CollectionOnetoManyInfo coli in classInfo.Collections1toN)
                {
                    prop            = new CodeMemberProperty();
                    prop.Name       = coli.Name;
                    prop.Attributes = MemberAttributes.Final | MemberAttributes.Public;
                    prop.Type       = GetCollectionPropertyType(coli.ClassName);

                    prop.GetStatements.Add(
                        new CodeConditionStatement(
                            new CodeBinaryOperatorExpression(
                                new CodeFieldReferenceExpression(This, "_collectionCache_" + coli.Name),
                                CodeBinaryOperatorType.IdentityEquality,
                                new CodePrimitiveExpression(null)), new CodeStatement[]
                    {
                        new CodeAssignStatement(
                            new CodeFieldReferenceExpression(This, "_collectionCache_" + coli.Name),
                            new CodeObjectCreateExpression(GetCollectionWrapperType(coli.ClassName),
                                                           new CodeObjectCreateExpression(new CodeTypeReference(typeof(Sooda.ObjectMapper.SoodaObjectOneToManyCollection)),
                                                                                          new CodeExpression[] {
                            new CodeMethodInvokeExpression(This, "GetTransaction"),
                            new CodeTypeOfExpression(new CodeTypeReference(coli.ClassName)),
                            new CodeThisReferenceExpression(),
                            new CodePrimitiveExpression(coli.ForeignFieldName),
                            new CodePropertyReferenceExpression(new CodeTypeReferenceExpression(coli.ClassName + "_Factory"), "TheClassInfo"),
                            new CodeFieldReferenceExpression(null, "_collectionWhere_" + coli.Name),
                            new CodePrimitiveExpression(coli.Cache)
                        }))),
                    }, new CodeStatement[] { }));

                    prop.GetStatements.Add(new CodeMethodReturnStatement(new CodeFieldReferenceExpression(This, "_collectionCache_" + coli.Name)));
                    ctd.Members.Add(prop);

#if DOTNET35
                    CodeExpression whereExpression = new CodeMethodInvokeExpression(
                        new CodeTypeReferenceExpression(typeof(Sooda.QL.Soql)),
                        "FieldEquals",
                        new CodePrimitiveExpression(coli.ForeignFieldName),
                        This);
                    if (!string.IsNullOrEmpty(coli.Where))
                    {
                        whereExpression = new CodeObjectCreateExpression(
                            typeof(Sooda.QL.SoqlBooleanAndExpression),
                            whereExpression,
                            new CodePropertyReferenceExpression(new CodeFieldReferenceExpression(null, "_collectionWhere_" + coli.Name), "WhereExpression"));
                    }
                    prop = GetCollectionLinqQuery(coli, whereExpression);
                    ctd.Members.Add(prop);
#endif
                }
            }

            if (classInfo.CollectionsNtoN != null)
            {
                foreach (CollectionManyToManyInfo coli in classInfo.CollectionsNtoN)
                {
                    RelationInfo relationInfo = coli.GetRelationInfo();
                    // FieldInfo masterField = relationInfo.Table.Fields[1 - coli.MasterField];

                    string relationTargetClass = relationInfo.Table.Fields[coli.MasterField].References;

                    prop            = new CodeMemberProperty();
                    prop.Name       = coli.Name;
                    prop.Attributes = MemberAttributes.Final | MemberAttributes.Public;
                    prop.Type       = GetCollectionPropertyType(relationTargetClass);

                    prop.GetStatements.Add(
                        new CodeConditionStatement(
                            new CodeBinaryOperatorExpression(
                                new CodeFieldReferenceExpression(This, "_collectionCache_" + coli.Name),
                                CodeBinaryOperatorType.IdentityEquality,
                                new CodePrimitiveExpression(null)), new CodeStatement[] {
                        new CodeAssignStatement(
                            new CodeFieldReferenceExpression(This, "_collectionCache_" + coli.Name),
                            new CodeObjectCreateExpression(GetCollectionWrapperType(relationTargetClass),
                                                           new CodeObjectCreateExpression(new CodeTypeReference(typeof(Sooda.ObjectMapper.SoodaObjectManyToManyCollection)),
                                                                                          new CodeExpression[] {
                            new CodeMethodInvokeExpression(This, "GetTransaction"),
                            new CodePrimitiveExpression(coli.MasterField),
                            new CodeMethodInvokeExpression(This, "GetPrimaryKeyValue"),
                            new CodeTypeOfExpression(relationInfo.Name + "_RelationTable"),
                            new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(relationInfo.Name + "_RelationTable"), "theRelationInfo")
                        }))
                            ),
                    }
                            , new CodeStatement[] { }));

                    prop.GetStatements.Add(new CodeMethodReturnStatement(new CodeFieldReferenceExpression(This, "_collectionCache_" + coli.Name)));

                    ctd.Members.Add(prop);

#if DOTNET35
                    CodeExpression whereExpression = new CodeMethodInvokeExpression(
                        new CodeTypeReferenceExpression(typeof(Sooda.QL.Soql)),
                        "CollectionFor",
                        new CodeMethodInvokeExpression(
                            new CodePropertyReferenceExpression(new CodeTypeReferenceExpression(classInfo.Name + "_Factory"), "TheClassInfo"),
                            "FindCollectionManyToMany",
                            new CodePrimitiveExpression(coli.Name)),
                        This);
                    prop = GetCollectionLinqQuery(coli, whereExpression);
                    ctd.Members.Add(prop);
#endif
                }
            }
        }