Beispiel #1
0
        /// <summary>
        /// Generate a proxy for the given entity type.
        /// </summary>
        /// <typeparam name="T">The entity type.</typeparam>
        /// <param name="entityKey">The entity key.</param>
        /// <returns>The proxy.</returns>
        public T GenerateForEntity <T>(string entityKey)
            where T : class
        {
            var type         = typeof(T);
            var typeMetadata = this.typeRepo.GetOrRegister(type) as EntityMetadata;

            if (typeMetadata == null)
            {
                throw new ArgumentException("The given type must be an entity type.");
            }

            var proxyTypeBuilder = new ProxyTypeBuilder(type);

            var dbKey = EntityKeyGenerator.GetDbKey(typeMetadata, entityKey);

            if (!this.dbClient.KeyExists(dbKey))
            {
                return(default(T));
            }

            // Generate proxy for key property.
            var keyPropTypeMetadata = this.typeRepo.Get(typeMetadata.KeyProperty.PropertyType);

            proxyTypeBuilder.InjectStub().CreateCtor().OverrideProperty(typeMetadata.KeyProperty, keyPropTypeMetadata, string.Concat(dbKey, typeMetadata.KeyProperty.Name), true);

            // Generate proxies for other properties.
            return(this.GenerateForObjectInternal <T>(proxyTypeBuilder, typeMetadata, dbKey));
        }
        /// <inheritdoc/>
        public IEnumerable <IDbOperation> GenerateObjectRecord(string prefix, object obj, TypeMetadata typeMetadata, bool generateRefForProxy = true)
        {
            // Traverse the property tree by using DFS.
            // This implemention is for better performance in case some object have too much layers.
            var states = new Stack <(Type type, string name, object val, string prefix, uint depth)>();
            var path   = new Dictionary <uint, object>();

            // Initialize the searching with the properties of the object.
            states.Push((typeMetadata.Type, null, obj, prefix, 0u));

            // Searching and build the database record.
            var visitedEntities = new HashSet <string>();

            while (states.Count != 0)
            {
                var(curType, curName, curValue, curPrefix, depth) = states.Pop();
                var curTypeMetadata = this.typeRepo.GetOrRegister(curType);
                path[depth] = curValue;

                // Process current property.
                curPrefix += curName;
                switch (curTypeMetadata)
                {
                case EntityMetadata entityType:
                    var entityKey      = EntityKeyGenerator.GetDbKey(entityType, curValue);
                    var entityKeyValue = EntityKeyGenerator.GetEntityKey(entityType, curValue);

                    // For added entity, just record the reference.
                    if (curName != null)
                    {
                        yield return(new DbStringRecord(curPrefix, entityKeyValue));
                    }

                    if (!visitedEntities.Contains(entityKey) && !(curValue is IProxy && generateRefForProxy))
                    {
                        // For new entity, add it to records.
                        visitedEntities.Add(entityKey);
                        yield return(new DbStringRecord(entityKey, bool.TrueString));

                        ExpandProperties(
                            states,
                            entityKey,
                            curValue,
                            entityType.Properties.Append(entityType.KeyProperty),
                            depth + 1);
                    }

                    break;

                case ObjectMetadata objType:
                    for (var i = 0u; i < depth; i++)
                    {
                        if (path[i] == curValue)
                        {
                            throw new NotSupportedException("Circular reference is not support Object type, consider use Entity instead.");
                        }
                    }

                    yield return(new DbStringRecord(curPrefix, bool.TrueString));

                    ExpandProperties(states, curPrefix, curValue, objType.Properties, depth + 1);
                    break;

                case ListMetadata listType:
                    var list = curValue as IList;
                    yield return(new DbStringRecord(curPrefix, list.Count.ToString()));

                    for (int i = 0; i < list.Count; i++)
                    {
                        states.Push((listType.InnerType, i.ToString(), list[i], curPrefix, depth + 1));
                    }

                    break;

                case TypeMetadata basicType when basicType.ValueType == ObjectValueType.Primitive || basicType.ValueType == ObjectValueType.String:
                    yield return(new DbStringRecord(curPrefix, curValue.ToString()));

                    break;

                default:
                    throw new NotSupportedException();
                }
            }
        }