/// <summary> /// Loads bulk copy options from deserialized xml /// </summary> /// <param name="def">The deserialized definition.</param> /// <param name="name">The name.</param> /// <param name="owner">if set to <c>true</c> [owner].</param> /// <returns></returns> public FdoBulkCopyOptions BulkCopyFromXml(FdoBulkCopyTaskDefinition def, ref string name, bool owner) { var nameMap = Prepare(def); // TODO/FIXME/HACK: // // The introduction of on-the-fly schema modifications before copying has introduced a // potential problem which will only occur when multiple copy tasks copy to the same target // feature class. // // What happens is because a target will be multiple sources copying to it, if we need // to create/update the target class definition, the current infrastructure will be confused // as to which source feature class to clone from. // // A possible solution is to return the first matching name. This will cause a "create" operation // to be queued. We then alter the pre-modification process so that subsequent "create" operations // becomes "update" operations instead. // // On second thought, the current infrastructure should be smart enought to prevent this, as // the UI only allows: // // 1. Mapping to an existing class // 2. Mapping to a class of the same name (create if necessary) // // It won't be possible to map to a class that doesn't exist, as the requirement for auto-create/update // is that the class name will be the same. // // ie. It won't be possible to create this mapping // // a. Foo -> Foo (create if necessary) // b. Bar -> Foo // // Rule 1 prevents mapping b) from happening // Rule 2 ensures that Foo will only ever be created once // // If multiple sources are mapped to the same target, I believe the bcp infrastructure should ensure // that target must already exist first. name = def.name; Dictionary<string, FdoConnection> connections = new Dictionary<string, FdoConnection>(); Dictionary<string, string> changeConnNames = new Dictionary<string, string>(); //TODO: Prepare() ensured that all connections have unique names that don't already exist //now in the effort to re-use existing connections, see which connection entries //already exist and can be renamed back to the old name foreach (FdoConnectionEntryElement entry in def.Connections) { string connName = entry.name; FdoConnection conn = CreateConnection(entry.provider, entry.ConnectionString, entry.configPath, ref connName); connections[connName] = conn; if (connName != entry.name) { changeConnNames[entry.name] = connName; } } foreach (string oldName in changeConnNames.Keys) { def.UpdateConnectionReferences(oldName, changeConnNames[oldName]); } //Compile the list of classes to be queried Dictionary<string, MultiSchemaQuery> queries = new Dictionary<string, MultiSchemaQuery>(); foreach (FdoCopyTaskElement task in def.CopyTasks) { MultiSchemaQuery src = null; MultiSchemaQuery dst = null; //Process source if (!queries.ContainsKey(task.Source.connection)) src = queries[task.Source.connection] = new MultiSchemaQuery(task.Source.connection, SchemaOrigin.Source); else src = queries[task.Source.connection]; var sq = src.TryGet(task.Source.schema); if (sq != null) { sq.AddClass(task.Source.@class); } else { sq = new SchemaQuery(task.Source.schema); sq.AddClass(task.Source.@class); src.Add(sq); } //Process target if (!queries.ContainsKey(task.Target.connection)) dst = queries[task.Target.connection] = new MultiSchemaQuery(task.Target.connection, SchemaOrigin.Target); else dst = queries[task.Target.connection]; var tq = dst.TryGet(task.Target.schema); if (tq != null) { tq.AddClass(task.Target.@class); } else { tq = new SchemaQuery(task.Target.schema); tq.AddClass(task.Target.@class); dst.Add(tq); } } List<TargetClassModificationItem> modifiers = new List<TargetClassModificationItem>(); using (var schemaCache = new FeatureSchemaCache()) { //Now populate the schema cache with source schemas foreach (string connName in queries.Keys) { if (connections.ContainsKey(connName)) { var mqry = queries[connName]; var conn = connections[connName]; FeatureSchemaCollection schemas = new FeatureSchemaCollection(null); using (var svc = conn.CreateFeatureService()) { foreach (var sq in mqry.SchemaQueries) { //Source schema queries are expected to fully check out so use original method if (mqry.Origin == SchemaOrigin.Source) { schemas.Add(svc.PartialDescribeSchema(sq.SchemaName, new List<string>(sq.ClassNames))); } } } if (schemas.Count > 0) schemaCache.Add(connName, schemas); } } //Now populate the schema cache with target schemas, taking note of any //classes that need to be created or updated. foreach (string connName in queries.Keys) { if (connections.ContainsKey(connName)) { var mqry = queries[connName]; var conn = connections[connName]; FeatureSchemaCollection schemas = new FeatureSchemaCollection(null); using (var svc = conn.CreateFeatureService()) { foreach (var sq in mqry.SchemaQueries) { //Source schema queries are expected to fully check out so use original method if (mqry.Origin == SchemaOrigin.Target) { //Because we may need to create new classes, the old method will break down on non-existent class names //So use the new method string[] notFound; var schema = svc.PartialDescribeSchema(sq.SchemaName, new List<string>(sq.ClassNames), out notFound); //if (notFound.Length > 0) //{ // //If we can't modify schemas we'll stop right here. This is caused by elements containing createIfNotExists = true // if (!conn.Capability.GetBooleanCapability(CapabilityType.FdoCapabilityType_SupportsSchemaModification)) // throw new NotSupportedException("The connection named " + connName + " does not support schema modification. Therefore, copy tasks and property/expression mappings cannot have createIfNotExists = true"); // //This cumbersome, but we need the parent schema name of the class that we will need to copy // string srcSchema = GetSourceSchemaForMapping(def, sq.SchemaName, notFound); // foreach (string className in notFound) // { // modifiers.Add(new CreateTargetClassFromSource(srcSchema, className)); // } //} schemas.Add(schema); } } } if (schemas.Count > 0) schemaCache.Add(connName, schemas); } } FdoBulkCopyOptions opts = new FdoBulkCopyOptions(connections, owner); foreach (FdoCopyTaskElement task in def.CopyTasks) { TargetClassModificationItem mod; FdoClassCopyOptions copt = FdoClassCopyOptions.FromElement(task, schemaCache, connections[task.Source.connection], connections[task.Target.connection], out mod); opts.AddClassCopyOption(copt); if (mod != null) copt.PreCopyTargetModifier = mod; //opts.AddClassModifier(mod); } return opts; } }
/// <summary> /// Loads bulk copy options from deserialized xml /// </summary> /// <param name="def">The deserialized definition.</param> /// <param name="name">The name.</param> /// <param name="owner">if set to <c>true</c> [owner].</param> /// <returns></returns> public FdoBulkCopyOptions BulkCopyFromXml(FdoBulkCopyTaskDefinition def, ref string name, bool owner) { var nameMap = Prepare(def); // TODO/FIXME/HACK: // // The introduction of on-the-fly schema modifications before copying has introduced a // potential problem which will only occur when multiple copy tasks copy to the same target // feature class. // // What happens is because a target will be multiple sources copying to it, if we need // to create/update the target class definition, the current infrastructure will be confused // as to which source feature class to clone from. // // A possible solution is to return the first matching name. This will cause a "create" operation // to be queued. We then alter the pre-modification process so that subsequent "create" operations // becomes "update" operations instead. // // On second thought, the current infrastructure should be smart enought to prevent this, as // the UI only allows: // // 1. Mapping to an existing class // 2. Mapping to a class of the same name (create if necessary) // // It won't be possible to map to a class that doesn't exist, as the requirement for auto-create/update // is that the class name will be the same. // // ie. It won't be possible to create this mapping // // a. Foo -> Foo (create if necessary) // b. Bar -> Foo // // Rule 1 prevents mapping b) from happening // Rule 2 ensures that Foo will only ever be created once // // If multiple sources are mapped to the same target, I believe the bcp infrastructure should ensure // that target must already exist first. name = def.name; Dictionary <string, FdoConnection> connections = new Dictionary <string, FdoConnection>(); Dictionary <string, string> changeConnNames = new Dictionary <string, string>(); //TODO: Prepare() ensured that all connections have unique names that don't already exist //now in the effort to re-use existing connections, see which connection entries //already exist and can be renamed back to the old name foreach (FdoConnectionEntryElement entry in def.Connections) { string connName = entry.name; FdoConnection conn = CreateConnection(entry.provider, entry.ConnectionString, entry.configPath, ref connName); connections[connName] = conn; if (connName != entry.name) { changeConnNames[entry.name] = connName; } } foreach (string oldName in changeConnNames.Keys) { def.UpdateConnectionReferences(oldName, changeConnNames[oldName]); } //Compile the list of classes to be queried Dictionary <string, MultiSchemaQuery> queries = new Dictionary <string, MultiSchemaQuery>(); foreach (FdoCopyTaskElement task in def.CopyTasks) { MultiSchemaQuery src = null; MultiSchemaQuery dst = null; //Process source if (!queries.ContainsKey(task.Source.connection)) { src = queries[task.Source.connection] = new MultiSchemaQuery(task.Source.connection, SchemaOrigin.Source); } else { src = queries[task.Source.connection]; } var sq = src.TryGet(task.Source.schema); if (sq != null) { sq.AddClass(task.Source.@class); } else { sq = new SchemaQuery(task.Source.schema); sq.AddClass(task.Source.@class); src.Add(sq); } //Process target if (!queries.ContainsKey(task.Target.connection)) { dst = queries[task.Target.connection] = new MultiSchemaQuery(task.Target.connection, SchemaOrigin.Target); } else { dst = queries[task.Target.connection]; } var tq = dst.TryGet(task.Target.schema); if (tq != null) { tq.AddClass(task.Target.@class); } else { tq = new SchemaQuery(task.Target.schema); tq.AddClass(task.Target.@class); dst.Add(tq); } } List <TargetClassModificationItem> modifiers = new List <TargetClassModificationItem>(); using (var schemaCache = new FeatureSchemaCache()) { //Now populate the schema cache with source schemas foreach (string connName in queries.Keys) { if (connections.ContainsKey(connName)) { var mqry = queries[connName]; var conn = connections[connName]; FeatureSchemaCollection schemas = new FeatureSchemaCollection(null); using (var svc = conn.CreateFeatureService()) { foreach (var sq in mqry.SchemaQueries) { //Source schema queries are expected to fully check out so use original method if (mqry.Origin == SchemaOrigin.Source) { schemas.Add(svc.PartialDescribeSchema(sq.SchemaName, new List <string>(sq.ClassNames))); } } } if (schemas.Count > 0) { schemaCache.Add(connName, schemas); } } } //Now populate the schema cache with target schemas, taking note of any //classes that need to be created or updated. foreach (string connName in queries.Keys) { if (connections.ContainsKey(connName)) { var mqry = queries[connName]; var conn = connections[connName]; FeatureSchemaCollection schemas = new FeatureSchemaCollection(null); using (var svc = conn.CreateFeatureService()) { foreach (var sq in mqry.SchemaQueries) { //Source schema queries are expected to fully check out so use original method if (mqry.Origin == SchemaOrigin.Target) { //Because we may need to create new classes, the old method will break down on non-existent class names //So use the new method string[] notFound; var schema = svc.PartialDescribeSchema(sq.SchemaName, new List <string>(sq.ClassNames), out notFound); //if (notFound.Length > 0) //{ // //If we can't modify schemas we'll stop right here. This is caused by elements containing createIfNotExists = true // if (!conn.Capability.GetBooleanCapability(CapabilityType.FdoCapabilityType_SupportsSchemaModification)) // throw new NotSupportedException("The connection named " + connName + " does not support schema modification. Therefore, copy tasks and property/expression mappings cannot have createIfNotExists = true"); // //This cumbersome, but we need the parent schema name of the class that we will need to copy // string srcSchema = GetSourceSchemaForMapping(def, sq.SchemaName, notFound); // foreach (string className in notFound) // { // modifiers.Add(new CreateTargetClassFromSource(srcSchema, className)); // } //} schemas.Add(schema); } } } if (schemas.Count > 0) { schemaCache.Add(connName, schemas); } } } FdoBulkCopyOptions opts = new FdoBulkCopyOptions(connections, owner); foreach (FdoCopyTaskElement task in def.CopyTasks) { TargetClassModificationItem mod; FdoClassCopyOptions copt = FdoClassCopyOptions.FromElement(task, schemaCache, connections[task.Source.connection], connections[task.Target.connection], out mod); opts.AddClassCopyOption(copt); if (mod != null) { copt.PreCopyTargetModifier = mod; } //opts.AddClassModifier(mod); } return(opts); } }
public void Add(SchemaQuery query) { _query.Add(query); }