예제 #1
0
 public IRedisTypedClient <T> As <T>()
 {
     try
     {
         var typedClient = new RedisTypedClient <T>(this);
         LicenseUtils.AssertValidUsage(LicenseFeature.Redis, QuotaType.Types, __uniqueTypes.Count);
         return(typedClient);
     }
     catch (TypeInitializationException ex)
     {
         throw ex.GetInnerMostException();
     }
 }
        /// <summary>
        /// Command to set multuple binary safe arguments
        /// </summary>
        /// <param name="cmdWithBinaryArgs"></param>
        /// <returns></returns>
        protected void WriteCommandToSendBuffer(params byte[][] cmdWithBinaryArgs)
        {
            Interlocked.Increment(ref __requestsPerHour);
            if (__requestsPerHour % 20 == 0)
            {
                LicenseUtils.AssertValidUsage(LicenseFeature.Redis, QuotaType.RequestsPerHour, __requestsPerHour);
            }

            if (log.IsDebugEnabled && !RedisConfig.DisableVerboseLogging)
            {
                CmdLog(cmdWithBinaryArgs);
            }

            //Total command lines count
            WriteAllToSendBuffer(cmdWithBinaryArgs);
        }
        // Should only be called at StartUp
        public static DynamoMetadataType RegisterTable(Type type)
        {
            if (Types == null)
            {
                Types = new HashSet <DynamoMetadataType>();
            }

            Types.RemoveWhere(x => x.Type == type);

            var table = ToMetadataTable(type);

            Types.Add(table);

            LicenseUtils.AssertValidUsage(LicenseFeature.Aws, QuotaType.Tables, Types.Count);

            RegisterTypes(type.GetReferencedTypes());

            return(table);
        }
예제 #4
0
        /// <summary>
        /// Command to set multuple binary safe arguments
        /// </summary>
        /// <param name="cmdWithBinaryArgs"></param>
        /// <returns></returns>
        protected bool SendCommand(params byte[][] cmdWithBinaryArgs)
        {
            if (!AssertConnectedSocket())
            {
                return(false);
            }

            Interlocked.Increment(ref __requestsPerHour);
            if (__requestsPerHour % 20 == 0)
            {
                LicenseUtils.AssertValidUsage(LicenseFeature.Redis, QuotaType.RequestsPerHour, __requestsPerHour);
            }

            try
            {
                CmdLog(cmdWithBinaryArgs);

                //Total command lines count
                WriteAllToSendBuffer(cmdWithBinaryArgs);

                //if (cmdBuffer.Count >= 100)
                //{
                //    FlushSendBuffer();
                //}

                //pipeline will handle flush, if pipelining is turned on
                if (Pipeline == null)
                {
                    FlushSendBuffer();
                }
            }
            catch (SocketException ex)
            {
                cmdBuffer.Clear();
                return(HandleSocketException(ex));
            }
            return(true);
        }
        internal static ModelDefinition GetModelDefinition(this Type modelType)
        {
            if (typeModelDefinitionMap.TryGetValue(modelType, out var modelDef))
            {
                return(modelDef);
            }

            if (modelType.IsValueType || modelType == typeof(string))
            {
                return(null);
            }

            var modelAliasAttr = modelType.FirstAttribute <AliasAttribute>();
            var schemaAttr     = modelType.FirstAttribute <SchemaAttribute>();

            var preCreate  = modelType.FirstAttribute <PreCreateTableAttribute>();
            var postCreate = modelType.FirstAttribute <PostCreateTableAttribute>();
            var preDrop    = modelType.FirstAttribute <PreDropTableAttribute>();
            var postDrop   = modelType.FirstAttribute <PostDropTableAttribute>();

            modelDef = new ModelDefinition
            {
                ModelType          = modelType,
                Name               = modelType.Name,
                Alias              = modelAliasAttr?.Name,
                Schema             = schemaAttr?.Name,
                PreCreateTableSql  = preCreate?.Sql,
                PostCreateTableSql = postCreate?.Sql,
                PreDropTableSql    = preDrop?.Sql,
                PostDropTableSql   = postDrop?.Sql,
            };

            modelDef.CompositeIndexes.AddRange(
                modelType.AllAttributes <CompositeIndexAttribute>().ToList());

            modelDef.UniqueConstraints.AddRange(
                modelType.AllAttributes <UniqueConstraintAttribute>().ToList());

            var objProperties = modelType.GetProperties(
                BindingFlags.Public | BindingFlags.Instance).ToList();

            var hasPkAttr = objProperties.Any(p => p.HasAttribute <PrimaryKeyAttribute>());

            var hasIdField = CheckForIdField(objProperties);

            var i = 0;

            foreach (var propertyInfo in objProperties)
            {
                if (propertyInfo.GetIndexParameters().Length > 0)
                {
                    continue; //Is Indexer
                }
                var sequenceAttr      = propertyInfo.FirstAttribute <SequenceAttribute>();
                var computeAttr       = propertyInfo.FirstAttribute <ComputeAttribute>();
                var computedAttr      = propertyInfo.FirstAttribute <ComputedAttribute>();
                var customSelectAttr  = propertyInfo.FirstAttribute <CustomSelectAttribute>();
                var decimalAttribute  = propertyInfo.FirstAttribute <DecimalLengthAttribute>();
                var belongToAttribute = propertyInfo.FirstAttribute <BelongToAttribute>();
                var isFirst           = i++ == 0;

                var isAutoId = propertyInfo.HasAttribute <AutoIdAttribute>();

                var isPrimaryKey = (!hasPkAttr && (propertyInfo.Name == OrmLiteConfig.IdField || (!hasIdField && isFirst))) ||
                                   propertyInfo.HasAttributeNamed(typeof(PrimaryKeyAttribute).Name) ||
                                   isAutoId;

                var isRowVersion = propertyInfo.Name == ModelDefinition.RowVersionName &&
                                   (propertyInfo.PropertyType == typeof(ulong) || propertyInfo.PropertyType == typeof(byte[]));

                var isNullableType = propertyInfo.PropertyType.IsNullableType();

                var isNullable = (!propertyInfo.PropertyType.IsValueType &&
                                  !propertyInfo.HasAttributeNamed(typeof(RequiredAttribute).Name)) ||
                                 isNullableType;

                var propertyType = isNullableType
                    ? Nullable.GetUnderlyingType(propertyInfo.PropertyType)
                    : propertyInfo.PropertyType;

                Type treatAsType = null;
                if (propertyType.IsEnumFlags() || propertyType.HasAttribute <EnumAsIntAttribute>())
                {
                    treatAsType = Enum.GetUnderlyingType(propertyType);
                }

                var aliasAttr = propertyInfo.FirstAttribute <AliasAttribute>();

                var indexAttr = propertyInfo.FirstAttribute <IndexAttribute>();
                var isIndex   = indexAttr != null;
                var isUnique  = isIndex && indexAttr.Unique;

                var stringLengthAttr = propertyInfo.CalculateStringLength(decimalAttribute);

                var defaultValueAttr = propertyInfo.FirstAttribute <DefaultAttribute>();

                var referencesAttr    = propertyInfo.FirstAttribute <ReferencesAttribute>();
                var referenceAttr     = propertyInfo.FirstAttribute <ReferenceAttribute>();
                var fkAttr            = propertyInfo.FirstAttribute <ForeignKeyAttribute>();
                var customFieldAttr   = propertyInfo.FirstAttribute <CustomFieldAttribute>();
                var chkConstraintAttr = propertyInfo.FirstAttribute <CheckConstraintAttribute>();

                var fieldDefinition = new FieldDefinition
                {
                    Name                  = propertyInfo.Name,
                    Alias                 = aliasAttr?.Name,
                    FieldType             = propertyType,
                    FieldTypeDefaultValue = propertyType.GetDefaultValue(),
                    TreatAsType           = treatAsType,
                    PropertyInfo          = propertyInfo,
                    IsNullable            = isNullable,
                    IsPrimaryKey          = isPrimaryKey,
                    AutoIncrement         =
                        isPrimaryKey &&
                        propertyInfo.HasAttribute <AutoIncrementAttribute>(),
                    AutoId             = isAutoId,
                    IsIndexed          = !isPrimaryKey && isIndex,
                    IsUniqueIndex      = isUnique,
                    IsClustered        = indexAttr?.Clustered == true,
                    IsNonClustered     = indexAttr?.NonClustered == true,
                    IndexName          = indexAttr?.Name,
                    IsRowVersion       = isRowVersion,
                    IgnoreOnInsert     = propertyInfo.HasAttribute <IgnoreOnInsertAttribute>(),
                    IgnoreOnUpdate     = propertyInfo.HasAttribute <IgnoreOnUpdateAttribute>(),
                    ReturnOnInsert     = propertyInfo.HasAttribute <ReturnOnInsertAttribute>(),
                    FieldLength        = stringLengthAttr?.MaximumLength,
                    DefaultValue       = defaultValueAttr?.DefaultValue,
                    CheckConstraint    = chkConstraintAttr?.Constraint,
                    IsUniqueConstraint = propertyInfo.HasAttribute <UniqueAttribute>(),
                    ForeignKey         = fkAttr == null
                        ? referencesAttr != null ? new ForeignKeyConstraint(referencesAttr.Type) : null
                        : new ForeignKeyConstraint(fkAttr.Type, fkAttr.OnDelete, fkAttr.OnUpdate, fkAttr.ForeignKeyName),
                    IsReference           = referenceAttr != null && propertyType.IsClass,
                    GetValueFn            = propertyInfo.CreateGetter(),
                    SetValueFn            = propertyInfo.CreateSetter(),
                    Sequence              = sequenceAttr?.Name,
                    IsComputed            = computeAttr != null || computedAttr != null || customSelectAttr != null,
                    ComputeExpression     = computeAttr != null ? computeAttr.Expression : string.Empty,
                    CustomSelect          = customSelectAttr?.Sql,
                    Scale                 = decimalAttribute?.Scale,
                    BelongToModelName     = belongToAttribute?.BelongToTableType.GetModelDefinition().ModelName,
                    CustomFieldDefinition = customFieldAttr?.Sql,
                    IsRefType             = propertyType.IsRefType(),
                };

                var isIgnored = propertyInfo.HasAttribute <IgnoreAttribute>() ||
                                fieldDefinition.IsReference;
                if (isIgnored)
                {
                    modelDef.IgnoredFieldDefinitions.Add(fieldDefinition);
                }
                else
                {
                    modelDef.FieldDefinitions.Add(fieldDefinition);
                }

                if (isRowVersion)
                {
                    modelDef.RowVersion = fieldDefinition;
                }
            }

            modelDef.AfterInit();

            Dictionary <Type, ModelDefinition> snapshot, newCache;

            do
            {
                snapshot = typeModelDefinitionMap;
                newCache = new Dictionary <Type, ModelDefinition>(typeModelDefinitionMap)
                {
                    [modelType] = modelDef
                };
            } while (!ReferenceEquals(
                         Interlocked.CompareExchange(ref typeModelDefinitionMap, newCache, snapshot), snapshot));

            LicenseUtils.AssertValidUsage(LicenseFeature.OrmLite, QuotaType.Tables, typeModelDefinitionMap.Count);

            return(modelDef);
        }
예제 #6
0
        internal static ModelDefinition GetModelDefinition(this Type modelType)
        {
            ModelDefinition modelDef;

            if (typeModelDefinitionMap.TryGetValue(modelType, out modelDef))
            {
                return(modelDef);
            }

            if (modelType.IsValueType() || modelType == typeof(string))
            {
                return(null);
            }

            var modelAliasAttr = modelType.FirstAttribute <AliasAttribute>();
            var schemaAttr     = modelType.FirstAttribute <SchemaAttribute>();

            var preCreate  = modelType.FirstAttribute <PreCreateTableAttribute>();
            var postCreate = modelType.FirstAttribute <PostCreateTableAttribute>();
            var preDrop    = modelType.FirstAttribute <PreDropTableAttribute>();
            var postDrop   = modelType.FirstAttribute <PostDropTableAttribute>();

            modelDef = new ModelDefinition
            {
                ModelType          = modelType,
                Name               = modelType.Name,
                Alias              = modelAliasAttr != null ? modelAliasAttr.Name : null,
                Schema             = schemaAttr != null ? schemaAttr.Name : null,
                PreCreateTableSql  = preCreate != null ? preCreate.Sql : null,
                PostCreateTableSql = postCreate != null ? postCreate.Sql : null,
                PreDropTableSql    = preDrop != null ? preDrop.Sql : null,
                PostDropTableSql   = postDrop != null ? postDrop.Sql : null,
            };

            modelDef.CompositeIndexes.AddRange(
                modelType.GetCustomAttributes(typeof(CompositeIndexAttribute), true).ToList()
                .ConvertAll(x => (CompositeIndexAttribute)x));

            var objProperties = modelType.GetProperties(
                BindingFlags.Public | BindingFlags.Instance).ToList();

            var hasPkAttr = objProperties.Any(p => p.HasAttribute <PrimaryKeyAttribute>());

            var hasIdField = CheckForIdField(objProperties);

            var i = 0;

            foreach (var propertyInfo in objProperties)
            {
                var sequenceAttr      = propertyInfo.FirstAttribute <SequenceAttribute>();
                var computeAttr       = propertyInfo.FirstAttribute <ComputeAttribute>();
                var decimalAttribute  = propertyInfo.FirstAttribute <DecimalLengthAttribute>();
                var belongToAttribute = propertyInfo.FirstAttribute <BelongToAttribute>();
                var isFirst           = i++ == 0;

                var isPrimaryKey = (!hasPkAttr && (propertyInfo.Name == OrmLiteConfig.IdField || (!hasIdField && isFirst))) ||
                                   propertyInfo.HasAttributeNamed(typeof(PrimaryKeyAttribute).Name);

                var isNullableType = IsNullableType(propertyInfo.PropertyType);

                var isNullable = (!propertyInfo.PropertyType.IsValueType &&
                                  !propertyInfo.HasAttributeNamed(typeof(RequiredAttribute).Name)) ||
                                 isNullableType;

                var propertyType = isNullableType
                    ? Nullable.GetUnderlyingType(propertyInfo.PropertyType)
                    : propertyInfo.PropertyType;

                Type treatAsType = null;
                if (propertyType.IsEnum && propertyType.HasAttribute <FlagsAttribute>())
                {
                    treatAsType = Enum.GetUnderlyingType(propertyType);
                }

                if (propertyType == typeof(TimeSpan))
                {
                    treatAsType = typeof(long);
                }

                var aliasAttr = propertyInfo.FirstAttribute <AliasAttribute>();

                var indexAttr = propertyInfo.FirstAttribute <IndexAttribute>();
                var isIndex   = indexAttr != null;
                var isUnique  = isIndex && indexAttr.Unique;

                var stringLengthAttr = propertyInfo.CalculateStringLength(decimalAttribute);

                var defaultValueAttr = propertyInfo.FirstAttribute <DefaultAttribute>();

                var referencesAttr  = propertyInfo.FirstAttribute <ReferencesAttribute>();
                var referenceAttr   = propertyInfo.FirstAttribute <ReferenceAttribute>();
                var foreignKeyAttr  = propertyInfo.FirstAttribute <ForeignKeyAttribute>();
                var customFieldAttr = propertyInfo.FirstAttribute <CustomFieldAttribute>();

                var fieldDefinition = new FieldDefinition
                {
                    Name          = propertyInfo.Name,
                    Alias         = aliasAttr != null ? aliasAttr.Name : null,
                    FieldType     = propertyType,
                    TreatAsType   = treatAsType,
                    PropertyInfo  = propertyInfo,
                    IsNullable    = isNullable,
                    IsPrimaryKey  = isPrimaryKey,
                    AutoIncrement =
                        isPrimaryKey &&
                        propertyInfo.HasAttributeNamed(typeof(AutoIncrementAttribute).Name),
                    IsIndexed      = isIndex,
                    IsUnique       = isUnique,
                    IsClustered    = indexAttr != null && indexAttr.Clustered,
                    IsNonClustered = indexAttr != null && indexAttr.NonClustered,
                    FieldLength    = stringLengthAttr != null
                        ? stringLengthAttr.MaximumLength
                        : (int?)null,
                    DefaultValue = defaultValueAttr != null ? defaultValueAttr.DefaultValue : null,
                    ForeignKey   = foreignKeyAttr == null
                        ? referencesAttr != null ? new ForeignKeyConstraint(referencesAttr.Type) : null
                        : new ForeignKeyConstraint(foreignKeyAttr.Type,
                                                   foreignKeyAttr.OnDelete,
                                                   foreignKeyAttr.OnUpdate,
                                                   foreignKeyAttr.ForeignKeyName),
                    IsReference           = referenceAttr != null && propertyType.IsClass,
                    GetValueFn            = propertyInfo.GetPropertyGetterFn(),
                    SetValueFn            = propertyInfo.GetPropertySetterFn(),
                    Sequence              = sequenceAttr != null ? sequenceAttr.Name : string.Empty,
                    IsComputed            = computeAttr != null,
                    ComputeExpression     = computeAttr != null ? computeAttr.Expression : string.Empty,
                    Scale                 = decimalAttribute != null ? decimalAttribute.Scale : (int?)null,
                    BelongToModelName     = belongToAttribute != null?belongToAttribute.BelongToTableType.GetModelDefinition().ModelName : null,
                    CustomFieldDefinition = customFieldAttr != null ? customFieldAttr.Sql                                                : null,
                };

                var isIgnored = propertyInfo.HasAttributeNamed(typeof(IgnoreAttribute).Name) ||
                                fieldDefinition.IsReference;
                if (isIgnored)
                {
                    modelDef.IgnoredFieldDefinitions.Add(fieldDefinition);
                }
                else
                {
                    modelDef.FieldDefinitions.Add(fieldDefinition);
                }
            }

            modelDef.SqlSelectAllFromTable = "SELECT {0} FROM {1} "
                                             .Fmt(OrmLiteConfig.DialectProvider.GetColumnNames(modelDef),
                                                  OrmLiteConfig.DialectProvider.GetQuotedTableName(modelDef));

            Dictionary <Type, ModelDefinition> snapshot, newCache;

            do
            {
                snapshot            = typeModelDefinitionMap;
                newCache            = new Dictionary <Type, ModelDefinition>(typeModelDefinitionMap);
                newCache[modelType] = modelDef;
            } while (!ReferenceEquals(
                         Interlocked.CompareExchange(ref typeModelDefinitionMap, newCache, snapshot), snapshot));

            LicenseUtils.AssertValidUsage(LicenseFeature.OrmLite, QuotaType.Tables, typeModelDefinitionMap.Count);

            return(modelDef);
        }
예제 #7
0
        public void Add(Type serviceType, Type requestType, Type responseType)
        {
            if (requestType.IsArray) //Custom AutoBatched requests
            {
                this.ServiceTypes.Add(serviceType);
                return;
            }

            this.ServiceTypes.Add(serviceType);
            this.RequestTypes.Add(requestType);

            var restrictTo = requestType.FirstAttribute <RestrictAttribute>()
                             ?? serviceType.FirstAttribute <RestrictAttribute>();

            var reqFilterAttrs = new[] { requestType, serviceType }
            .SelectMany(x => x.AllAttributes().OfType <IRequestFilterBase>()).ToList();
            var resFilterAttrs = (responseType != null ? new[] { responseType, serviceType } : new[] { serviceType })
                                 .SelectMany(x => x.AllAttributes().OfType <IResponseFilterBase>()).ToList();

            var authAttrs = reqFilterAttrs.OfType <AuthenticateAttribute>().ToList();
            var actions   = serviceType.GetRequestActions(requestType);

            authAttrs.AddRange(actions.SelectMany(x => x.AllAttributes <AuthenticateAttribute>()));
            var tagAttrs = requestType.AllAttributes <TagAttribute>().ToList();

            var operation = new Operation
            {
                ServiceType              = serviceType,
                RequestType              = requestType,
                ResponseType             = responseType,
                RestrictTo               = restrictTo,
                Actions                  = actions.Select(x => x.NameUpper).Distinct().ToList(),
                Routes                   = new List <RestPath>(),
                RequestFilterAttributes  = reqFilterAttrs,
                ResponseFilterAttributes = resFilterAttrs,
                RequiresAuthentication   = authAttrs.Count > 0,
                RequiredRoles            = authAttrs.OfType <RequiredRoleAttribute>().SelectMany(x => x.RequiredRoles).ToList(),
                RequiresAnyRole          = authAttrs.OfType <RequiresAnyRoleAttribute>().SelectMany(x => x.RequiredRoles).ToList(),
                RequiredPermissions      = authAttrs.OfType <RequiredPermissionAttribute>().SelectMany(x => x.RequiredPermissions).ToList(),
                RequiresAnyPermission    = authAttrs.OfType <RequiresAnyPermissionAttribute>().SelectMany(x => x.RequiredPermissions).ToList(),
                Tags = tagAttrs,
            };

            this.OperationsMap[requestType] = operation;
            this.OperationNamesMap[operation.Name.ToLowerInvariant()] = operation;
            if (responseType != null)
            {
                this.ResponseTypes.Add(responseType);
                this.OperationsResponseMap[responseType] = operation;
            }

            //Only count non-core ServiceStack Services, i.e. defined outside of ServiceStack.dll or Swagger
            var nonCoreServicesCount = OperationsMap.Values
                                       .Count(x => x.ServiceType.Assembly != typeof(Service).Assembly &&
                                              x.ServiceType.FullName != "ServiceStack.Api.Swagger.SwaggerApiService" &&
                                              x.ServiceType.FullName != "ServiceStack.Api.Swagger.SwaggerResourcesService" &&
                                              x.ServiceType.FullName != "ServiceStack.Api.OpenApi.OpenApiService" &&
                                              x.ServiceType.Name != "__AutoQueryServices" &&
                                              x.ServiceType.Name != "__AutoQueryDataServices");

            LicenseUtils.AssertValidUsage(LicenseFeature.ServiceStack, QuotaType.Operations, nonCoreServicesCount);
        }
예제 #8
0
        internal static ModelDefinition GetModelDefinition(this Type modelType)
        {
            if (typeModelDefinitionMap.TryGetValue(modelType, out var modelDef))
            {
                return(modelDef);
            }

            if (modelType.IsValueType || modelType == typeof(string))
            {
                return(null);
            }

            var modelAliasAttr = modelType.FirstAttribute <AliasAttribute>();
            var schemaAttr     = modelType.FirstAttribute <SchemaAttribute>();

            var preCreates  = modelType.AllAttributes <PreCreateTableAttribute>();
            var postCreates = modelType.AllAttributes <PostCreateTableAttribute>();
            var preDrops    = modelType.AllAttributes <PreDropTableAttribute>();
            var postDrops   = modelType.AllAttributes <PostDropTableAttribute>();

            string JoinSql(List <string> statements)
            {
                if (statements.Count == 0)
                {
                    return(null);
                }
                var sb = StringBuilderCache.Allocate();

                foreach (var sql in statements)
                {
                    if (sb.Length > 0)
                    {
                        sb.AppendLine(";");
                    }
                    sb.Append(sql);
                }
                var to = StringBuilderCache.ReturnAndFree(sb);

                return(to);
            }

            modelDef = new ModelDefinition
            {
                ModelType          = modelType,
                Name               = modelType.Name,
                Alias              = modelAliasAttr?.Name,
                Schema             = schemaAttr?.Name,
                PreCreateTableSql  = JoinSql(preCreates.Map(x => x.Sql)),
                PostCreateTableSql = JoinSql(postCreates.Map(x => x.Sql)),
                PreDropTableSql    = JoinSql(preDrops.Map(x => x.Sql)),
                PostDropTableSql   = JoinSql(postDrops.Map(x => x.Sql)),
            };

            modelDef.CompositeIndexes.AddRange(
                modelType.AllAttributes <CompositeIndexAttribute>().ToList());

            modelDef.UniqueConstraints.AddRange(
                modelType.AllAttributes <UniqueConstraintAttribute>().ToList());

            var objProperties = modelType.GetProperties(
                BindingFlags.Public | BindingFlags.Instance).ToList();

            var hasPkAttr = objProperties.Any(p => p.HasAttributeCached <PrimaryKeyAttribute>());

            var hasIdField = CheckForIdField(objProperties);

            var i = 0;
            var propertyInfoIdx = 0;

            foreach (var propertyInfo in objProperties)
            {
                if (propertyInfo.GetIndexParameters().Length > 0)
                {
                    continue; //Is Indexer
                }
                var sequenceAttr       = propertyInfo.FirstAttribute <SequenceAttribute>();
                var computeAttr        = propertyInfo.FirstAttribute <ComputeAttribute>();
                var computedAttr       = propertyInfo.FirstAttribute <ComputedAttribute>();
                var persistedAttr      = propertyInfo.FirstAttribute <PersistedAttribute>();
                var customSelectAttr   = propertyInfo.FirstAttribute <CustomSelectAttribute>();
                var decimalAttribute   = propertyInfo.FirstAttribute <DecimalLengthAttribute>();
                var belongToAttribute  = propertyInfo.FirstAttribute <BelongToAttribute>();
                var referenceAttr      = propertyInfo.FirstAttribute <ReferenceAttribute>();
                var referenceFieldAttr = propertyInfo.FirstAttribute <ReferenceFieldAttribute>();

                var isRowVersion = propertyInfo.Name == ModelDefinition.RowVersionName &&
                                   (propertyInfo.PropertyType == typeof(ulong) || propertyInfo.PropertyType == typeof(byte[]));

                var isNullableType = propertyInfo.PropertyType.IsNullableType();

                var isNullable = (!propertyInfo.PropertyType.IsValueType &&
                                  !propertyInfo.HasAttributeNamed(nameof(RequiredAttribute))) ||
                                 isNullableType;

                var propertyType = isNullableType
                    ? Nullable.GetUnderlyingType(propertyInfo.PropertyType)
                    : propertyInfo.PropertyType;


                Type treatAsType = null;

                if (propertyType.IsEnum)
                {
                    var enumKind = Converters.EnumConverter.GetEnumKind(propertyType);
                    if (enumKind == EnumKind.Int)
                    {
                        treatAsType = Enum.GetUnderlyingType(propertyType);
                    }
                    else if (enumKind == EnumKind.Char)
                    {
                        treatAsType = typeof(char);
                    }
                }

                var isReference = referenceAttr != null || referenceFieldAttr != null;
                var isIgnored   = propertyInfo.HasAttributeCached <IgnoreAttribute>() || isReference;

                var isFirst = !isIgnored && i++ == 0;

                var isAutoId = propertyInfo.HasAttributeCached <AutoIdAttribute>();

                var isPrimaryKey = (!hasPkAttr && (propertyInfo.Name == OrmLiteConfig.IdField || (!hasIdField && isFirst))) ||
                                   propertyInfo.HasAttributeNamed(nameof(PrimaryKeyAttribute)) ||
                                   isAutoId;

                var isAutoIncrement = isPrimaryKey && propertyInfo.HasAttributeCached <AutoIncrementAttribute>();

                if (isAutoIncrement && propertyInfo.PropertyType == typeof(Guid))
                {
                    throw new NotSupportedException($"[AutoIncrement] is only valid for integer properties for {modelType.Name}.{propertyInfo.Name} Guid property use [AutoId] instead");
                }

                if (isAutoId && (propertyInfo.PropertyType == typeof(int) || propertyInfo.PropertyType == typeof(long)))
                {
                    throw new NotSupportedException($"[AutoId] is only valid for Guid properties for {modelType.Name}.{propertyInfo.Name} integer property use [AutoIncrement] instead");
                }

                var aliasAttr = propertyInfo.FirstAttribute <AliasAttribute>();

                var indexAttr = propertyInfo.FirstAttribute <IndexAttribute>();
                var isIndex   = indexAttr != null;
                var isUnique  = isIndex && indexAttr.Unique;

                var stringLengthAttr = propertyInfo.CalculateStringLength(decimalAttribute);

                var defaultValueAttr = propertyInfo.FirstAttribute <DefaultAttribute>();

                var referencesAttr    = propertyInfo.FirstAttribute <ReferencesAttribute>();
                var fkAttr            = propertyInfo.FirstAttribute <ForeignKeyAttribute>();
                var customFieldAttr   = propertyInfo.FirstAttribute <CustomFieldAttribute>();
                var chkConstraintAttr = propertyInfo.FirstAttribute <CheckConstraintAttribute>();

                var order = propertyInfoIdx++;
                if (customFieldAttr != null)
                {
                    order = customFieldAttr.Order;
                }

                var fieldDefinition = new FieldDefinition
                {
                    ModelDef              = modelDef,
                    Name                  = propertyInfo.Name,
                    Alias                 = aliasAttr?.Name,
                    FieldType             = propertyType,
                    FieldTypeDefaultValue = isNullable ? null : propertyType.GetDefaultValue(),
                    TreatAsType           = treatAsType,
                    PropertyInfo          = propertyInfo,
                    IsNullable            = isNullable,
                    IsPrimaryKey          = isPrimaryKey,
                    AutoIncrement         = isPrimaryKey && isAutoIncrement,
                    AutoId                = isAutoId,
                    IsIndexed             = !isPrimaryKey && isIndex,
                    IsUniqueIndex         = isUnique,
                    IsClustered           = indexAttr?.Clustered == true,
                    IsNonClustered        = indexAttr?.NonClustered == true,
                    IndexName             = indexAttr?.Name,
                    IsRowVersion          = isRowVersion,
                    IgnoreOnInsert        = propertyInfo.HasAttributeCached <IgnoreOnInsertAttribute>(),
                    IgnoreOnUpdate        = propertyInfo.HasAttributeCached <IgnoreOnUpdateAttribute>(),
                    ReturnOnInsert        = propertyInfo.HasAttributeCached <ReturnOnInsertAttribute>(),
                    FieldLength           = stringLengthAttr?.MaximumLength,
                    DefaultValue          = defaultValueAttr?.DefaultValue,
                    CheckConstraint       = chkConstraintAttr?.Constraint,
                    IsUniqueConstraint    = propertyInfo.HasAttributeCached <UniqueAttribute>(),
                    ForeignKey            = fkAttr == null
                        ? referencesAttr != null ? new ForeignKeyConstraint(referencesAttr.Type) : null
                        : new ForeignKeyConstraint(fkAttr.Type, fkAttr.OnDelete, fkAttr.OnUpdate, fkAttr.ForeignKeyName),
                    IsReference           = isReference,
                    GetValueFn            = propertyInfo.CreateGetter(),
                    SetValueFn            = propertyInfo.CreateSetter(),
                    Sequence              = sequenceAttr?.Name,
                    IsComputed            = computeAttr != null || computedAttr != null || customSelectAttr != null,
                    IsPersisted           = persistedAttr != null,
                    ComputeExpression     = computeAttr != null ? computeAttr.Expression : string.Empty,
                    CustomSelect          = customSelectAttr?.Sql,
                    CustomInsert          = propertyInfo.FirstAttribute <CustomInsertAttribute>()?.Sql,
                    CustomUpdate          = propertyInfo.FirstAttribute <CustomUpdateAttribute>()?.Sql,
                    Scale                 = decimalAttribute?.Scale,
                    BelongToModelName     = belongToAttribute?.BelongToTableType.GetModelDefinition().ModelName,
                    CustomFieldDefinition = customFieldAttr?.Sql,
                    IsRefType             = propertyType.IsRefType(),
                    Order                 = order
                };

                if (referenceFieldAttr != null)
                {
                    fieldDefinition.FieldReference = new FieldReference(fieldDefinition)
                    {
                        RefModel = referenceFieldAttr.Model,
                        RefId    = referenceFieldAttr.Id,
                        RefField = referenceFieldAttr.Field ?? propertyInfo.Name,
                    };
                }

                if (isIgnored)
                {
                    modelDef.IgnoredFieldDefinitions.Add(fieldDefinition);
                }
                else
                {
                    modelDef.FieldDefinitions.Add(fieldDefinition);
                }

                if (isRowVersion)
                {
                    modelDef.RowVersion = fieldDefinition;
                }
            }

            modelDef.AfterInit();

            Dictionary <Type, ModelDefinition> snapshot, newCache;

            do
            {
                snapshot = typeModelDefinitionMap;
                newCache = new Dictionary <Type, ModelDefinition>(typeModelDefinitionMap)
                {
                    [modelType] = modelDef
                };
            } while (!ReferenceEquals(
                         Interlocked.CompareExchange(ref typeModelDefinitionMap, newCache, snapshot), snapshot));

            LicenseUtils.AssertValidUsage(LicenseFeature.OrmLite, QuotaType.Tables, typeModelDefinitionMap.Count);

            return(modelDef);
        }