private void btnSave_Click(object sender, EventArgs e) { if (mTreeView.Nodes[0].Nodes.Count == 0) { MessageService.ShowMessage("Please define at least one copy task"); return; } if (string.IsNullOrEmpty(txtName.Text)) { MessageService.ShowMessage("Please specify a name for this task"); return; } TaskManager tmgr = ServiceManager.Instance.GetService <TaskManager>(); if (IsNew && tmgr.GetTask(txtName.Text) != null) { MessageService.ShowMessage("A task named " + txtName.Text + " already exists. Please specify a name for this task"); return; } //This could take a while... using (new TempCursor(Cursors.WaitCursor)) { LoggingService.Info("Updating loaded task. Please wait."); TaskLoader loader = new TaskLoader(); if (IsNew) { string name = string.Empty; FdoBulkCopyOptions opts = loader.BulkCopyFromXml(Save(), ref name, false); FdoBulkCopy bcp = new FdoBulkCopy(opts); tmgr.AddTask(name, bcp); this.Close(); } else { FdoBulkCopy bcp = tmgr.GetTask(txtName.Text) as FdoBulkCopy; if (bcp == null) { MessageService.ShowMessage("This named task is not a bulk copy task or could not find the named task to update"); return; } string name = string.Empty; FdoBulkCopyOptions opts = loader.BulkCopyFromXml(Save(), ref name, false); Debug.Assert(name == txtName.Text); //unchanged //Update options bcp.Options = opts; MessageService.ShowMessage("Task updated. To save to disk, right-click the task object and choose: " + ResourceService.GetString("CMD_SaveTask")); this.Close(); } } }
public void Load() { TaskLoader ldr = new TaskLoader(); string path = Preferences.SessionDirectory; if (System.IO.Directory.Exists(path)) { string[] files = System.IO.Directory.GetFiles(path, "*" + TaskDefinitionHelper.BULKCOPYDEFINITION); foreach (string f in files) { try { string name = string.Empty; FdoBulkCopyOptions opt = ldr.BulkCopyFromXml(f, ref name, false); FdoBulkCopy cpy = new FdoBulkCopy(opt); AddTask(name, cpy); } catch { } } files = System.IO.Directory.GetFiles(path, "*" + TaskDefinitionHelper.JOINDEFINITION); foreach (string f in files) { try { string name = string.Empty; FdoJoinOptions opt = ldr.JoinFromXml(f, ref name, false); FdoJoin join = new FdoJoin(opt); AddTask(name, join); } catch { } } files = System.IO.Directory.GetFiles(path, "*" + TaskDefinitionHelper.SEQUENTIALPROCESS); foreach (string f in files) { try { string prefix = Path.GetFileNameWithoutExtension(f); string name = prefix; int counter = 0; while (this.NameExists(name)) { counter++; name = prefix + counter; } SequentialProcessDefinition spd = (SequentialProcessDefinition)SequentialProcessDefinition.Serializer.Deserialize(File.OpenRead(f)); FdoSequentialProcess proc = new FdoSequentialProcess(spd); AddTask(name, proc); } catch { } } } }
public override void Run() { TaskManager mgr = ServiceManager.Instance.GetService <TaskManager>(); TaskLoader ldr = new TaskLoader(); string file = FileService.OpenFile(ResourceService.GetString("TITLE_LOAD_TASK"), ResourceService.GetString("FILTER_TASK_DEFINITION")); if (FileService.FileExists(file)) { using (new TempCursor(Cursors.WaitCursor)) { LoggingService.Info(ResourceService.GetString("LOADING_TASK_DEFINITION_WAIT")); if (TaskDefinitionHelper.IsBulkCopy(file)) { string name = string.Empty; FdoBulkCopyOptions opt = ldr.BulkCopyFromXml(file, ref name, false); FdoBulkCopy cpy = new FdoBulkCopy(opt); mgr.AddTask(name, cpy); } else if (TaskDefinitionHelper.IsJoin(file)) { string name = string.Empty; FdoJoinOptions opt = ldr.JoinFromXml(file, ref name, false); FdoJoin join = new FdoJoin(opt); mgr.AddTask(name, join); } else if (TaskDefinitionHelper.IsSequentialProcess(file)) { using (var fs = File.OpenRead(file)) { int counter = 0; var prefix = Path.GetFileNameWithoutExtension(file); var name = prefix; while (mgr.NameExists(name)) { counter++; name = prefix + counter; } var def = (SequentialProcessDefinition)SequentialProcessDefinition.Serializer.Deserialize(fs); var proc = new FdoSequentialProcess(def); mgr.AddTask(name, proc); } } } } }
/// <summary> /// Handles the file drop /// </summary> /// <param name="file">The file being dropped</param> public void HandleDrop(string file) { TaskManager mgr = ServiceManager.Instance.GetService <TaskManager>(); TaskLoader ldr = new TaskLoader(); string prefix = string.Empty; FdoBulkCopyOptions opt = ldr.BulkCopyFromXml(file, ref prefix, false); FdoBulkCopy cpy = new FdoBulkCopy(opt); string name = prefix; int counter = 0; while (mgr.NameExists(name)) { counter++; name = prefix + counter; } mgr.AddTask(name, cpy); }
/// <summary> /// Utility method to create a bulk copy operation from /// one class to another /// </summary> /// <param name="sourceConn"></param> /// <param name="targetConn"></param> /// <param name="srcSchemaName"></param> /// <param name="srcQuery"></param> /// <param name="targetSchemaName"></param> /// <param name="targetClassName"></param> /// <param name="propertyMapping"></param> /// <returns></returns> public static FdoBulkCopy CreateBulkCopy( FdoConnection sourceConn, FdoConnection targetConn, string srcSchemaName, FeatureQueryOptions srcQuery, string targetSchemaName, string targetClassName, NameValueCollection propertyMapping) { var dict = new Dictionary <string, FdoConnection>(); dict["SOURCE"] = sourceConn; dict["TARGET"] = targetConn; var opts = new FdoBulkCopyOptions(dict, false); var copt = new FdoClassCopyOptions( "SOURCE", "TARGET", srcSchemaName, srcQuery.ClassName, targetSchemaName, targetClassName); if (!string.IsNullOrEmpty(srcQuery.Filter)) { copt.SourceFilter = srcQuery.Filter; } foreach (string p in propertyMapping.Keys) { copt.AddPropertyMapping(p, propertyMapping[p]); } copt.FlattenGeometries = true; copt.ForceWkb = true; opts.AddClassCopyOption(copt); return(new FdoBulkCopy(opts, 100)); }
/// <summary> /// Creates a FDO bulk copy task. The target file will be created as part of /// this method call. If the target path is a directory, it is assumed that /// SHP files are to be created and copied to. /// </summary> /// <param name="sourceFile">The path to the source file.</param> /// <param name="targetPath"> /// The path to the target file/directory. If it is a directory, it is assumed /// that SHP files are to be created and copied to. /// </param> /// <param name="copySpatialContexts">If true, will also copy spatial contexts</param> /// <param name="fixIncompatibleSchema">If true, will try to fix the source schema to make it compatible with the target connection. If false, an exception will be thrown</param> /// <param name="flattenGeometries">If true, will strip all Z and M coordinates from all geometries that are copied</param> /// <returns></returns> public static FdoBulkCopy CreateBulkCopy(string sourceFile, string targetPath, bool copySpatialContexts, bool fixIncompatibleSchema, bool flattenGeometries) { FdoBulkCopyOptions options = null; FdoConnection source = null; FdoConnection target = null; try { //Is a directory. Implies a SHP connection if (IsShp(targetPath)) { //SHP doesn't actually support CreateDataStore. We use the following technique: // - Connect to base directory // - Clone source schema and apply to SHP connection. // - A SHP file and related files are created for each feature class. string shpdir = Directory.Exists(targetPath) ? targetPath : Path.GetDirectoryName(targetPath); source = CreateFlatFileConnection(sourceFile); target = new FdoConnection("OSGeo.SHP", "DefaultFileLocation=" + shpdir); source.Open(); //Verify source has only classes with single geometry storage and only one geometry using (FdoFeatureService svc = source.CreateFeatureService()) { using (FeatureSchemaCollection schemas = svc.DescribeSchema()) { foreach (FeatureSchema sch in schemas) { foreach (ClassDefinition cd in sch.Classes) { int geomProps = 0; foreach (PropertyDefinition pd in cd.Properties) { if (pd.PropertyType == PropertyType.PropertyType_GeometricProperty) { GeometricPropertyDefinition gp = pd as GeometricPropertyDefinition; GeometricType[] types = FdoGeometryUtil.GetGeometricTypes(gp.GeometryTypes); if (types.Length != 1 || (types.Length == 1 && types[0] == GeometricType.GeometricType_All)) { throw new FdoETLException(string.Format("Source file cannot be copied to a SHP file. {0}:{1}.{2} has more than one geometry storage type", sch.Name, cd.Name, pd.Name)); } geomProps++; } } if (geomProps > 1) { throw new FdoETLException("Source file cannot be copied to a SHP file. One or more feature classes have more than one geometry property"); } } } } } } else { if (!CreateFlatFileDataSource(targetPath)) { throw new FdoException("Unable to create data source on: " + targetPath); } source = CreateFlatFileConnection(sourceFile); target = CreateFlatFileConnection(targetPath); } //Source and target connections may have been opened before this point if (source.State == FdoConnectionState.Closed) { source.Open(); } if (target.State == FdoConnectionState.Closed) { target.Open(); } string srcName = "SOURCE"; string dstName = "TARGET"; Dictionary <string, FdoConnection> connections = new Dictionary <string, FdoConnection>(); connections.Add(srcName, source); connections.Add(dstName, target); options = new FdoBulkCopyOptions(connections, true); if (copySpatialContexts) { CopyAllSpatialContexts(source, target, true); } using (FdoFeatureService srcService = source.CreateFeatureService()) using (FdoFeatureService destService = target.CreateFeatureService()) { FeatureSchemaCollection schemas = srcService.DescribeSchema(); //Assume single-schema FeatureSchema fs = schemas[0]; //Clone and apply to target FeatureSchema targetSchema = FdoSchemaUtil.CloneSchema(fs); IncompatibleSchema incSchema; string sourceSchemaName = fs.Name; string targetSchemaName = string.Empty; bool canApply = destService.CanApplySchema(targetSchema, out incSchema); if (canApply) { destService.ApplySchema(targetSchema); targetSchemaName = targetSchema.Name; } else { if (fixIncompatibleSchema) { FeatureSchema fixedSchema = destService.AlterSchema(targetSchema, incSchema); destService.ApplySchema(fixedSchema); targetSchemaName = fixedSchema.Name; } else { throw new Exception(incSchema.ToString()); } } //Copy all classes foreach (ClassDefinition cd in fs.Classes) { FdoClassCopyOptions copt = new FdoClassCopyOptions(srcName, dstName, sourceSchemaName, cd.Name, targetSchemaName, cd.Name); copt.Name = "Copy source to target [" + cd.Name + "]"; copt.FlattenGeometries = flattenGeometries; options.AddClassCopyOption(copt); //Flick on batch support if we can if (destService.SupportsBatchInsertion()) { copt.BatchSize = 300; //Madness? THIS IS SPARTA! } } } } catch (Exception) { if (source != null) { source.Dispose(); } if (target != null) { target.Dispose(); } throw; } return(new FdoBulkCopy(options)); }
private void Load(FdoBulkCopyOptions def, string name) { txtName.Text = name; grdConnections.Rows.Clear(); foreach (string connName in def.ConnectionNames) { this.AddParticipatingConnection(connName); } TreeNode root = mTreeView.Nodes[0]; foreach (FdoClassCopyOptions task in def.ClassCopyOptions) { //Init w/ defaults CopyTaskNodeDecorator dec = AddNewTask( root, task.SourceConnectionName, task.SourceSchema, task.SourceClassName, task.TargetConnectionName, task.TargetSchema, task.TargetClassName, task.Name, task.CreateIfNotExists); _tasks[dec.DecoratedNode.Index] = dec; root.Expand(); btnSave.Enabled = (root.Nodes.Count > 0); //Options dec.Options.BatchSize = task.BatchSize; dec.Options.Delete = task.DeleteTarget; dec.Options.SourceFilter = task.SourceFilter; dec.Options.Flatten = task.FlattenGeometries; var checkProps = new List <string>(task.CheckSourceProperties); //Property Mappings foreach (string srcProp in task.SourcePropertyNames) { string dstProp = task.GetTargetProperty(srcProp); bool createIfNotExists = checkProps.Contains(srcProp); try { dec.PropertyMappings.MapProperty(srcProp, dstProp, createIfNotExists); } catch (MappingException ex) { LoggingService.Info("Skipping mapping: " + srcProp + " => " + dstProp + " (" + ex.Message + ")"); } FdoDataPropertyConversionRule rule = task.GetDataConversionRule(srcProp); PropertyConversionNodeDecorator cd = dec.PropertyMappings.GetConversionRule(srcProp); if (rule != null) { cd.NullOnFailedConversion = rule.NullOnFailure; cd.Truncate = rule.Truncate; } } //Expression Mappings foreach (string alias in task.SourceAliases) { string expr = task.GetExpression(alias); string dstProp = task.GetTargetPropertyForAlias(alias); bool createIfNotExists = checkProps.Contains(alias); dec.ExpressionMappings.AddExpression(alias, expr); dec.ExpressionMappings.MapExpression(alias, dstProp, createIfNotExists); FdoDataPropertyConversionRule rule = task.GetDataConversionRule(alias); PropertyConversionNodeDecorator cd = dec.ExpressionMappings.GetConversionRule(alias); if (rule != null) { cd.NullOnFailedConversion = rule.NullOnFailure; cd.Truncate = rule.Truncate; } } } }
public override int Execute() { CommandStatus retCode; DefinitionLoader loader = new DefinitionLoader(); string name = null; if (TaskDefinitionHelper.IsBulkCopy(_file)) { FdoBulkCopyTaskDefinition def = null; using (var sr = new StreamReader(_file)) { XmlSerializer ser = new XmlSerializer(typeof(FdoBulkCopyTaskDefinition)); def = (FdoBulkCopyTaskDefinition)ser.Deserialize(sr); } if (def == null) { return((int)CommandStatus.E_FAIL_TASK_VALIDATION); } //If more than one task specified, load the default task and weed //out unneeded elements. if (_taskNames.Length > 0) { base.WriteLine("Certain tasks have been specified, only part of the bulk copy definition will execute"); var keepConnections = new Dictionary <string, FdoConnectionEntryElement>(); var keepTasks = new List <FdoCopyTaskElement>(); //Store needed tasks foreach (var task in def.CopyTasks) { if (Array.IndexOf(_taskNames, task.name) >= 0) { keepTasks.Add(task); } } //Store needed connections foreach (var task in keepTasks) { foreach (var conn in def.Connections) { //Is referenced as source/target connection? if (task.Source.connection == conn.name || task.Target.connection == conn.name) { if (!keepConnections.ContainsKey(conn.name)) { keepConnections.Add(conn.name, conn); } } } } if (keepTasks.Count != _taskNames.Length) { List <string> names = new List <string>(); foreach (var n in _taskNames) { bool found = false; foreach (var task in keepTasks) { if (task.name == n) { found = true; break; } } if (!found) { names.Add(n); } } base.WriteError("Could not find specified tasks in bulk copy definition: " + string.Join(",", names.ToArray())); return((int)CommandStatus.E_FAIL_MISSING_BULK_COPY_TASKS); } //Now replace def.Connections = new List <FdoConnectionEntryElement>(keepConnections.Values).ToArray(); def.CopyTasks = keepTasks.ToArray(); } using (FdoBulkCopyOptions opts = loader.BulkCopyFromXml(def, ref name, true)) { FdoBulkCopy copy = new FdoBulkCopy(opts); copy.ProcessMessage += delegate(object sender, MessageEventArgs e) { base.WriteLine(e.Message); }; copy.ProcessAborted += delegate(object sender, EventArgs e) { base.WriteLine("Bulk Copy Aborted"); }; copy.ProcessCompleted += delegate(object sender, EventArgs e) { base.WriteLine("Bulk Copy Completed"); }; copy.Execute(); List <Exception> errors = new List <Exception>(copy.GetAllErrors()); if (errors.Count > 0) { string file = GenerateLogFileName("bcp-error-"); LogErrors(errors, file); base.WriteError("Errors were encountered during bulk copy."); retCode = CommandStatus.E_FAIL_BULK_COPY_WITH_ERRORS; } else { retCode = CommandStatus.E_OK; } } } else if (TaskDefinitionHelper.IsJoin(_file)) { if (_taskNames.Length > 0) { base.WriteError("Parameter -bcptask is not applicable for join tasks"); return((int)CommandStatus.E_FAIL_INVALID_ARGUMENTS); } using (FdoJoinOptions opts = loader.JoinFromXml(_file, ref name, true)) { opts.Left.Connection.Open(); opts.Right.Connection.Open(); opts.Target.Connection.Open(); FdoJoin join = new FdoJoin(opts); join.ProcessMessage += delegate(object sender, MessageEventArgs e) { base.WriteLine(e.Message); }; join.Execute(); List <Exception> errors = new List <Exception>(join.GetAllErrors()); if (errors.Count > 0) { string file = GenerateLogFileName("join-error-"); LogErrors(errors, file); base.WriteError("Errors were encountered during join operation"); retCode = CommandStatus.E_FAIL_JOIN_WITH_ERRORS; } else { retCode = CommandStatus.E_OK; } } } else if (TaskDefinitionHelper.IsSequentialProcess(_file)) { var def = (SequentialProcessDefinition)SequentialProcessDefinition.Serializer.Deserialize(File.OpenRead(_file)); var proc = new FdoSequentialProcess(def); proc.ProcessMessage += delegate(object sender, MessageEventArgs e) { base.WriteLine(e.Message); }; proc.Execute(); List <Exception> errors = new List <Exception>(proc.GetAllErrors()); if (errors.Count > 0) { string file = GenerateLogFileName("seq-process-"); LogErrors(errors, file); base.WriteError("Errors were encountered during sequential process"); } //Why E_OK? the user should check the log for the underlying return codes //of individual FdoUtil.exe invocations! retCode = CommandStatus.E_OK; } else { retCode = CommandStatus.E_FAIL_UNRECOGNISED_TASK_FORMAT; } return((int)retCode); }
public override int Execute() { CommandStatus retCode; FdoConnection srcConn = new FdoConnection(_srcProvider, _srcConnStr); FdoConnection destConn = null; //Directory given, assume SHP if (Directory.Exists(_destPath)) { destConn = new FdoConnection("OSGeo.SHP", "DefaultFileLocation=" + _destPath); } else { if (ExpressUtility.CreateFlatFileDataSource(_destPath)) { destConn = ExpressUtility.CreateFlatFileConnection(_destPath); } else { throw new FdoException("Could not create data source: " + _destPath); } } try { srcConn.Open(); destConn.Open(); string srcName = "SOURCE"; string dstName = "TARGET"; FdoBulkCopyOptions options = new FdoBulkCopyOptions(); options.RegisterConnection(srcName, srcConn); options.RegisterConnection(dstName, destConn); using (FdoFeatureService srcService = srcConn.CreateFeatureService()) using (FdoFeatureService destService = destConn.CreateFeatureService()) { //See if spatial context needs to be copied to target if (!string.IsNullOrEmpty(_srcSpatialContext)) { SpatialContextInfo srcCtx = srcService.GetSpatialContext(_srcSpatialContext); if (srcCtx != null) { Console.WriteLine("Copying spatial context: " + srcCtx.Name); ExpressUtility.CopyAllSpatialContexts(new SpatialContextInfo[] { srcCtx }, destConn, true); } } else { //Copy all ExpressUtility.CopyAllSpatialContexts(srcConn, destConn, true); } FeatureSchema srcSchema = null; //See if partial class list is needed if (_srcClasses.Count > 0) { WriteLine("Checking if partial schema discovery is supported: " + srcService.SupportsPartialSchemaDiscovery()); srcSchema = srcService.PartialDescribeSchema(_srcSchema, _srcClasses); } else //Full copy { WriteLine("No classes specified, reading full source schema"); srcSchema = srcService.GetSchemaByName(_srcSchema); } if (srcSchema == null) { WriteError("Could not find source schema: " + _srcSchema); retCode = CommandStatus.E_FAIL_SCHEMA_NOT_FOUND; } else { WriteLine("Checking source schema for incompatibilities"); FeatureSchema targetSchema = null; IncompatibleSchema incSchema; if (destService.CanApplySchema(srcSchema, out incSchema)) { int clsCount = srcSchema.Classes.Count; WriteLine("Applying source schema (containing " + clsCount + " classes) to target"); destService.ApplySchema(srcSchema, null, true); targetSchema = srcSchema; } else { WriteWarning("Incompatibilities were detected in source schema. Applying a modified version to target"); FeatureSchema fixedSchema = destService.AlterSchema(srcSchema, incSchema); int clsCount = fixedSchema.Classes.Count; WriteLine("Applying modified source schema (containing " + clsCount + " classes) to target"); destService.ApplySchema(fixedSchema, null, true); targetSchema = fixedSchema; } //Now set class copy options foreach (ClassDefinition cd in srcSchema.Classes) { FdoClassCopyOptions copt = new FdoClassCopyOptions(srcName, dstName, srcSchema.Name, cd.Name, targetSchema.Name, cd.Name); copt.FlattenGeometries = _flatten; options.AddClassCopyOption(copt); } if (_flatten) { WriteWarning("The switch -flatten has been defined. Geometries that are copied will have any Z or M coordinates removed"); } FdoBulkCopy copy = new FdoBulkCopy(options); copy.ProcessMessage += new MessageEventHandler(OnMessage); copy.ProcessCompleted += new EventHandler(OnCompleted); Console.WriteLine("Executing bulk copy"); copy.Execute(); List <Exception> errors = new List <Exception>(copy.GetAllErrors()); if (errors.Count > 0) { string file = GenerateLogFileName("bcp-error-"); LogErrors(errors, file); base.WriteError("Errors were encountered during bulk copy."); retCode = CommandStatus.E_FAIL_BULK_COPY_WITH_ERRORS; } else { retCode = CommandStatus.E_OK; } retCode = CommandStatus.E_OK; } } } catch (Exception ex) { WriteException(ex); retCode = CommandStatus.E_FAIL_UNKNOWN; } finally { srcConn.Dispose(); destConn.Dispose(); } return((int)retCode); }
/// <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); } }