public override bool IsModified(MappingEntity entity, object instance, object original)
        {
            if (base.IsModified(entity, instance, original))
                return true;

            // need to check nested entities too
            foreach (var mi in this.GetMappedMembers(entity))
            {
                if (this.IsNestedEntity(entity, mi))
                {
                    MappingEntity nested = this.GetRelatedEntity(entity, mi);
                    if (this.IsModified(nested, mi.GetValue(instance), mi.GetValue(original)))
                        return true;
                }
            }

            return false;
        }
        public override object CloneEntity(MappingEntity entity, object instance)
        {
            object clone = base.CloneEntity(entity, instance);

            // need to clone nested entities too
            foreach (var mi in this.GetMappedMembers(entity))
            {
                if (this.IsNestedEntity(entity, mi))
                {
                    MappingEntity nested = this.GetRelatedEntity(entity, mi);
                    var nestedValue = mi.GetValue(instance);
                    if (nestedValue != null)
                    {
                        var nestedClone = this.CloneEntity(nested, mi.GetValue(instance));
                        mi.SetValue(clone, nestedClone);
                    }
                }
            }

            return clone;
        }
        // make a variable declaration / initialization for dependent generated values
        private CommandExpression GetDependentGeneratedVariableDeclaration(MappingEntity entity, MappingTable table, List<MemberInfo> members, Expression instance, Dictionary<MemberInfo, Expression> map)
        {
            // first make command that retrieves the generated ids if any
            DeclarationCommand genIdCommand = null;
            var generatedIds = this.mapping.GetMappedMembers(entity).Where(m => this.mapping.IsPrimaryKey(entity, m) && this.mapping.IsIdentity(entity, m)).ToList();
            if (generatedIds.Count > 0)
            {
                genIdCommand = this.GetGeneratedIdCommand(entity, members, map);

                // if that's all there is then just return the generated ids
                if (members.Count == generatedIds.Count)
                {
                    return genIdCommand;
                }
            }

            // next make command that retrieves the generated members
            // only consider members that were not generated ids
            members = members.Except(generatedIds).ToList();

            var tableAlias = new TableAlias();
            var tex = new TableExpression(tableAlias, entity, this.mapping.GetTableName(table));

            Expression where = null;
            if (generatedIds.Count > 0)
            {
                where = generatedIds.Select((m, i) =>
                    this.GetMemberExpression(tex, entity, m).Equal(map[m])
                    ).Aggregate((x, y) => x.And(y));
            }
            else
            {
                where = this.GetIdentityCheck(tex, entity, instance);
            }

            TableAlias selectAlias = new TableAlias();
            var columns = new List<ColumnDeclaration>();
            var variables = new List<VariableDeclaration>();
            foreach (var mi in members)
            {
                ColumnExpression col = (ColumnExpression)this.GetMemberExpression(tex, entity, mi);
                columns.Add(new ColumnDeclaration(this.mapping.GetColumnName(entity, mi), col, col.QueryType));
                ColumnExpression vcol = new ColumnExpression(col.Type, col.QueryType, selectAlias, col.Name);
                variables.Add(new VariableDeclaration(mi.Name, col.QueryType, vcol));
                map.Add(mi, new VariableExpression(mi.Name, col.Type, col.QueryType));
            }

            var genMembersCommand = new DeclarationCommand(variables, new SelectExpression(selectAlias, columns, tex, where));

            if (genIdCommand != null)
            {
                return new BlockCommand(genIdCommand, genMembersCommand);
            }

            return genMembersCommand;
        }
 /// <summary>
 /// Get an expression that represents the delete operation for the specified instance.
 /// </summary>
 /// <param name="entity"></param>
 /// <param name="instance"></param>
 /// <param name="deleteCheck"></param>
 /// <returns></returns>
 public abstract Expression GetDeleteExpression(MappingEntity entity, Expression instance, LambdaExpression deleteCheck);
 /// <summary>
 /// Get an expression that represents the update operation for the specified instance.
 /// </summary>
 /// <param name="entity">The entity.</param>
 /// <param name="instance">The instance.</param>
 /// <param name="updateCheck">The update check.</param>
 /// <param name="selector">The selector.</param>
 /// <param name="indeedColumns">The indeed columns.</param>
 /// <param name="else">The @else.</param>
 /// <returns></returns>
 public abstract Expression GetUpdateExpression(MappingEntity entity, Expression instance, LambdaExpression updateCheck, LambdaExpression selector, ColumnIndeedExpression indeedColumns, Expression @else);
 /// <summary>
 /// Get an expression that represents the insert operation for the specified instance.
 /// </summary>
 /// <param name="entity"></param>
 /// <param name="instance">The instance to insert.</param>
 /// <param name="selector">A lambda expression that computes a return value from the operation.</param>
 /// <returns></returns>
 public abstract Expression GetInsertExpression(MappingEntity entity, Expression instance, LambdaExpression selector);
 /// <summary>
 /// Gets an expression that constructs an entity instance relative to a root.
 /// The root is most often a TableExpression, but may be any other experssion such as
 /// a ConstantExpression.
 /// </summary>
 /// <param name="root"></param>
 /// <param name="entity"></param>
 /// <returns></returns>
 public abstract EntityExpression GetEntityExpression(Expression root, MappingEntity entity);
 /// <summary>
 /// Determines whether the specified entity is modified.
 /// </summary>
 /// <param name="entity">The entity.</param>
 /// <param name="instance">The instance.</param>
 /// <param name="original">The original.</param>
 /// <returns>
 /// 	<c>true</c> if the specified entity is modified; otherwise, <c>false</c>.
 /// </returns>
 public abstract bool IsModified(MappingEntity entity, object instance, object original);
 /// <summary>
 /// Gets the depending entities.
 /// </summary>
 /// <param name="entity">The entity.</param>
 /// <param name="instance">The instance.</param>
 /// <returns></returns>
 public abstract IEnumerable<EntityInfo> GetDependingEntities(MappingEntity entity, object instance);
        public override Expression GetDeleteExpression(MappingEntity entity, Expression instance, LambdaExpression deleteCheck)
        {
            var tables = this.mapping.GetTables(entity);
            if (tables.Count < 2)
            {
                return base.GetDeleteExpression(entity, instance, deleteCheck);
            }

            var commands = new List<Expression>();
            foreach (var table in this.GetDependencyOrderedTables(entity).Reverse())
            {
                TableExpression tex = new TableExpression(new TableAlias(), entity, this.mapping.GetTableName(table));
                var where = this.GetIdentityCheck(tex, entity, instance);
                commands.Add(new DeleteCommand(tex, where));
            }

            Expression block = new BlockCommand(commands);

            if (deleteCheck != null)
            {
                var test = this.GetEntityStateTest(entity, instance, deleteCheck);
                return new IFCommand(test, block, null);
            }

            return block;
        }
        private Expression GetIdentityCheck(TableExpression root, MappingEntity entity, Expression instance, MappingTable table)
        {
            if (this.mapping.IsExtensionTable(table))
            {
                var keyColNames = this.mapping.GetExtensionKeyColumnNames(table).ToArray();
                var relatedMembers = this.mapping.GetExtensionRelatedMembers(table).ToArray();

                Expression where = null;
                for (int i = 0, n = keyColNames.Length; i < n; i++)
                {
                    var relatedMember = relatedMembers[i];
                    var cex = new ColumnExpression(TypeHelper.GetMemberType(relatedMember), this.GetColumnType(entity, relatedMember), root.Alias, keyColNames[n]);
                    var nex = this.GetMemberExpression(instance, entity, relatedMember);
                    var eq = cex.Equal(nex);
                    where = (where != null) ? where.And(eq) : where;
                }
                return where;
            }
            else
            {
                return base.GetIdentityCheck(root, entity, instance);
            }
        }
        public override Expression GetUpdateExpression(MappingEntity entity, Expression instance, LambdaExpression updateCheck, LambdaExpression selector, Expression @else)
        {
            var tables = this.mapping.GetTables(entity);
            if (tables.Count < 2)
            {
                return base.GetUpdateExpression(entity, instance, updateCheck, selector, @else);
            }

            var commands = new List<Expression>();
            foreach (var table in this.GetDependencyOrderedTables(entity))
            {
                TableExpression tex = new TableExpression(new TableAlias(), entity, this.mapping.GetTableName(table));
                var assignments = this.GetColumnAssignments(tex, instance, entity, (e, m) => this.mapping.GetAlias(e, m) == this.mapping.GetAlias(table) && this.mapping.IsUpdatable(e, m), null);
                var where = this.GetIdentityCheck(tex, entity, instance);
                commands.Add(new UpdateCommand(tex, where, assignments));
            }

            if (selector != null)
            {
                commands.Add(
                    new IFCommand(
                        this.Translator.Linguist.Language.GetRowsAffectedExpression(commands[commands.Count-1]).GreaterThan(Expression.Constant(0)),
                        this.GetUpdateResult(entity, instance, selector),
                        @else
                        )
                    );
            }
            else if (@else != null)
            {
                commands.Add(
                    new IFCommand(
                        this.Translator.Linguist.Language.GetRowsAffectedExpression(commands[commands.Count-1]).LessThanOrEqual(Expression.Constant(0)),
                        @else,
                        null
                        )
                    );
            }

            Expression block = new BlockCommand(commands);

            if (updateCheck != null)
            {
                var test = this.GetEntityStateTest(entity, instance, updateCheck);
                return new IFCommand(test, block, null);
            }

            return block;
        }
 private IEnumerable<ColumnAssignment> GetRelatedColumnAssignments(Expression expr, MappingEntity entity, MappingTable table, Dictionary<MemberInfo, Expression> map)
 {
     if (this.mapping.IsExtensionTable(table))
     {
         var keyColumns = this.mapping.GetExtensionKeyColumnNames(table).ToArray();
         var relatedMembers = this.mapping.GetExtensionRelatedMembers(table).ToArray();
         for (int i = 0, n = keyColumns.Length; i < n; i++)
         {
             MemberInfo member = relatedMembers[i];
             Expression exp = map[member];
             yield return new ColumnAssignment((ColumnExpression)this.GetMemberExpression(expr, entity, member), exp);
         }
     }
 }
 public override bool IsRelationship(MappingEntity entity, MemberInfo member)
 {
     return base.IsRelationship(entity, member)
         || this.IsNestedEntity(entity, member);
 }
 private IEnumerable<ColumnAssignment> GetColumnAssignments(
     Expression table, Expression instance, MappingEntity entity,
     Func<MappingEntity, MemberInfo, bool> fnIncludeColumn,
     Dictionary<MemberInfo, Expression> map)
 {
     foreach (var m in this.mapping.GetMappedMembers(entity))
     {
         if (this.mapping.IsColumn(entity, m) && fnIncludeColumn(entity, m))
         {
             yield return new ColumnAssignment(
                 (ColumnExpression)this.GetMemberExpression(table, entity, m),
                 this.GetMemberAccess(instance, m, map)
                 );
         }
         else if (this.mapping.IsNestedEntity(entity, m))
         {
             var assignments = this.GetColumnAssignments(
                 table, 
                 Expression.MakeMemberAccess(instance, m), 
                 this.mapping.GetRelatedEntity(entity, m), 
                 fnIncludeColumn, 
                 map
                 );
             foreach (var ca in assignments)
             {
                 yield return ca;
             }
         }
     }
 }
 /// <summary>
 /// 获取映射实体对象的主键对象。
 /// </summary>
 /// <param name="entity">The entity.</param>
 /// <param name="instance">The instance.</param>
 /// <returns></returns>
 public abstract object GetPrimaryKey(MappingEntity entity, object instance);
 /// <summary>
 /// 通过表达式获取映射实体对象的主键对象。
 /// </summary>
 /// <param name="entity">The entity.</param>
 /// <param name="source">The source.</param>
 /// <param name="keys">The keys.</param>
 /// <returns></returns>
 public abstract Expression GetPrimaryKeyQuery(MappingEntity entity, Expression source, Expression[] keys);
 public virtual IEnumerable<MappingTable> GetDependencyOrderedTables(MappingEntity entity)
 {
     var lookup = this.mapping.GetTables(entity).ToLookup(t => this.mapping.GetAlias(t));
     return this.mapping.GetTables(entity).Sort(t => this.mapping.IsExtensionTable(t) ? lookup[this.mapping.GetExtensionRelatedAlias(t)] : null);
 }
 /// <summary>
 /// Clones the entity.
 /// </summary>
 /// <param name="entity">The entity.</param>
 /// <param name="instance">The instance.</param>
 /// <returns></returns>
 public abstract object CloneEntity(MappingEntity entity, object instance);
 /// <summary>
 /// 获取映射实体的成员列表。
 /// </summary>
 /// <param name="entity">The entity.</param>
 /// <returns></returns>
 public abstract IEnumerable<MemberInfo> GetMappedMembers(MappingEntity entity);
 /// <summary>
 /// Get a query expression that selects all entities from a table
 /// </summary>
 /// <param name="entity">The entity.</param>
 /// <returns></returns>
 public abstract ProjectionExpression GetQueryExpression(MappingEntity entity);
 /// <summary>
 /// 判断指定的映射实体成员是否是主键列。
 /// </summary>
 /// <param name="entity"></param>
 /// <param name="member"></param>
 /// <returns></returns>
 public abstract bool IsPrimaryKey(MappingEntity entity, MemberInfo member);
 /// <summary>
 /// Get an expression for a mapped property relative to a root expression. 
 /// The root is either a TableExpression or an expression defining an entity instance.
 /// </summary>
 /// <param name="root"></param>
 /// <param name="entity"></param>
 /// <param name="member"></param>
 /// <returns></returns>
 public abstract Expression GetMemberExpression(Expression root, MappingEntity entity, MemberInfo member);
 /// <summary>
 /// Gets the primary key members.
 /// </summary>
 /// <param name="entity">The entity.</param>
 /// <returns></returns>
 public virtual IEnumerable<MemberInfo> GetPrimaryKeyMembers(MappingEntity entity)
 {
     return this.GetMappedMembers(entity).Where(m => this.IsPrimaryKey(entity, m));
 }
 /// <summary>
 /// Get an expression that represents the insert operation for the specified instance.
 /// </summary>
 /// <param name="entity">The entity.</param>
 /// <param name="instance">The instance to insert.</param>
 /// <param name="selector">A lambda expression that computes a return value from the operation.</param>
 /// <param name="indeedColumns">指定需要插入的列.</param>
 /// <returns></returns>
 public abstract Expression GetInsertExpression(MappingEntity entity, Expression instance, LambdaExpression selector, ColumnIndeedExpression indeedColumns);
 /// <summary>
 /// 判断指定映射实体的成员是否被影射为关联实体。
 /// </summary>
 /// <param name="entity">指定映射实体</param>
 /// <param name="member">成员</param>
 /// <returns></returns>
 public abstract bool IsRelationship(MappingEntity entity, MemberInfo member);
 /// <summary>
 /// Get an expression that represents the insert-or-update operation for the specified instance.
 /// </summary>
 /// <param name="entity"></param>
 /// <param name="instance"></param>
 /// <param name="updateCheck"></param>
 /// <param name="resultSelector"></param>
 /// <returns></returns>
 public abstract Expression GetInsertOrUpdateExpression(MappingEntity entity, Expression instance, LambdaExpression updateCheck, LambdaExpression resultSelector);
 /// <summary>
 /// Determines if a relationship property refers to a single entity (as opposed to a collection.)
 /// 判断知道的映射实体的成员是否是单一实体映射关联。
 /// </summary>
 /// <param name="entity">The entity.</param>
 /// <param name="member">The member.</param>
 /// <returns>
 /// 	<c>true</c> if [is singleton relationship] [the specified entity]; otherwise, <c>false</c>.
 /// </returns>
 public virtual bool IsSingletonRelationship(MappingEntity entity, MemberInfo member)
 {
     if (!this.IsRelationship(entity, member))
         return false;
     Type ieType = TypeHelper.FindIEnumerable(TypeHelper.GetMemberType(member));
     return ieType == null;
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="EntityInfo"/> struct.
 /// </summary>
 /// <param name="instance">The instance.</param>
 /// <param name="mapping">The mapping.</param>
 public EntityInfo(object instance, MappingEntity mapping)
 {
     this.instance = instance;
     this.mapping = mapping;
 }
 private Dictionary<string, List<MemberInfo>> GetDependentGeneratedColumns(MappingEntity entity)
 {
     return
         (from xt in this.mapping.GetTables(entity).Where(t => this.mapping.IsExtensionTable(t))
          group xt by this.mapping.GetExtensionRelatedAlias(xt))
         .ToDictionary(
             g => g.Key,
             g => g.SelectMany(xt => this.mapping.GetExtensionRelatedMembers(xt)).Distinct().ToList()
         );
 }