I have a requirement where I need to dump my Excel data in SQL Server table. The excel files could be varying (different no. of columns each time) and for each excel source file a new table has to be created everytime in SQL Server.
I tried with SSIS tasks coming across things that Mapping between input/output columns has to be predefined in package. Also, the destination table I am dumping data in has to be present before executing "OLE DB Destination" task.
To overcome some limitations, I did few workarounds:
Created a sample table in my database with 50 columns (because that is the max. columns I can have at any point of time in my source excel).
Before package executes I take a copy of that sample table giving it a name as I need to have different tables for each source.
Passing Excel source file dynamically to package through c# code and SSIS Variables.
Since my initial mapping is between 50 input/output columns in package, when the next excel reaches package with less no. of columns, package execution fails.
I am running the package through c# code, also when i independently run this package in BIDS passing SSIS variable value there itself, it fails with invalid column references error.
I have to run this package through code and I can't everytime remap it on failure.
I can't paste a snapshot of Package as of my reputation on this forum. Its a simple package with 2 tasks i.e. 'Excel Source' & 'OLE DB Destination'. The only issue I am facing is with dynamic mapping in package. Rest all is working fine.
Please help me out with this. Thanks in Advance!!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Microsoft.SqlServer.Dts.Runtime;
namespace SSRSReports
{
public partial class About : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
btnpkg.Visible = true;
}
protected void btnpkg_Click(object sender, EventArgs e)
{
string newtableName = "DATA_MD0000001_I606423";
string sourceExcel = FileUpload1.PostedFile.FileName;
DataQuery(newtableName);
RunPackage(sourceExcel, newtableName);
}
public void DataQuery(string newtableName)
{
DataClasses1DataContext dc = new DataClasses1DataContext();
dc.ExecuteCommand("select * into" + " " + newtableName + " " + "from DummyTable");
}
public void RunPackage(string SourceExcelPath, string DestinationTableName)
{
string pkgLocation;
Package pkg;
Application app;
DTSExecResult pkgResults;
Variables vars;
lblResults.Visible = false;
pkgLocation =
#"C:\Visual Studio 2008\Projects\DemoProject\DemoProject\Package.dtsx";
app = new Application();
pkg = app.LoadPackage(pkgLocation, null);
vars = pkg.Variables;
vars["SourceExcelFile"].Value = SourceExcelPath;
vars["DestinationTableName"].Value = DestinationTableName;
pkgResults = pkg.Execute(null, vars, null, null, null);
if (pkgResults == DTSExecResult.Success)
lblResults.Text = "Package ran successfully";
else
lblResults.Text = "Package failed";
lblResults.Visible = true;
}
}
}
Related
I have successfully started a console app solution in Visual Studio 2019, in C#, and have downloaded and installed the package DocumentFormat.OpenXML.DotNet.Core from NuGet. Since DocumentFormat.OpenXML does not play with .NET Core, I cannot use that. I have also successfully attached the package to the solution, and it appears in the Solution Explorer with no alerts. (Same method I have used in the past with other packages.)
This package is supposed to give my solution access to the OpenXML functionality, but I cannot get my program to recognize it.
I have tried inserting a using statement for DocumentFormat, but I get an error that the using statement is not necessary - and then it asks if I am missing a using statement or assembler reference.
I have tried changing the namespace to DocumentFormat, but then I have to add all the classes and all the functions, which it seems to me is the entire purpose of the package.
Here is the code (it's sample code just to get this working):
using System;
using DocumentFormat;
using S = DocumentFormat.OpenXml.Spreadsheet.Sheets;
using E = DocumentFormat.OpenXml.OpenXmlElement;
using A = DocumentFormat.OpenXml.OpenXmlAttribute;
namespace ConsoleApp1
{
class Program
{
static void ReadExcelFile()
{
try
{
//Lets open the existing excel file and read through its content . Open the excel using openxml sdk
using (SpreadsheetDocument doc = SpreadsheetDocument.Open("testdata.xlsx", false))
{
//create the object for workbook part
WorkbookPart workbookPart = doc.WorkbookPart;
Sheets thesheetcollection = workbookPart.Workbook.GetFirstChild<Sheets>();
StringBuilder excelResult = new StringBuilder();
//using for each loop to get the sheet from the sheetcollection
foreach (Sheet thesheet in thesheetcollection)
{
excelResult.AppendLine("Excel Sheet Name : " + thesheet.Name);
excelResult.AppendLine("----------------------------------------------- ");
//statement to get the worksheet object by using the sheet id
Worksheet theWorksheet = ((WorksheetPart)workbookPart.GetPartById(thesheet.Id)).Worksheet;
SheetData thesheetdata = (SheetData)theWorksheet.GetFirstChild<SheetData>();
foreach (Row thecurrentrow in thesheetdata)
{
foreach (Cell thecurrentcell in thecurrentrow)
{
//statement to take the integer value
string currentcellvalue = string.Empty;
if (thecurrentcell.DataType != null)
{
if (thecurrentcell.DataType == CellValues.SharedString)
{
int id;
if (Int32.TryParse(thecurrentcell.InnerText, out id))
{
SharedStringItem item = workbookPart.SharedStringTablePart.SharedStringTable.Elements<SharedStringItem>().ElementAt(id);
if (item.Text != null)
{
//code to take the string value
excelResult.Append(item.Text.Text + " ");
}
else if (item.InnerText != null)
{
currentcellvalue = item.InnerText;
}
else if (item.InnerXml != null)
{
currentcellvalue = item.InnerXml;
}
}
}
}
else
{
excelResult.Append(Convert.ToInt16(thecurrentcell.InnerText) + " ");
}
}
excelResult.AppendLine();
}
excelResult.Append("");
Console.WriteLine(excelResult.ToString());
Console.ReadLine();
}
}
}
catch (Exception)
{
}
}
}
}
I have refreshed the package,
I have started a new solution and added the package to it before typing anything in the code window,
I have tried updating and reinstalling both in the NuGet Package Manager Console and in the Manage NuGet Packages for Solution window.
Can someone please tell me what I'm missing?
Thanks in advance,
DJ
Not sure how you determined that the Open XML SDK as provided in the DocumentFormat.OpenXml NuGet package "does not play with .NET Core". As a contributor to the Open XML SDK, I can confirm that it definitely does play with .NET Core and you can clone my CodeSnippets GitHub repository to test this yourself. That repository contains a solution with multiple projects, a few of which use .NET Core (e.g., the CodeSnippets library, which targets netstandard2.0, and the CodeSnippets.Tests library, which targets netcoreapp3.0).
The DocumentFormat.OpenXml.DotNet.Core NuGet package that you use was last updated on July 30, 2016, i.e., almost four years ago. You should really replace this with the official DocumentFormat.OpenXml NuGet package.
I want to use the Teamfoundation.SourceControl.WebApi to check for updates or local changes against our TFS Source Control.
I can gather information about changesets from an item which is committed TFS but I am not able to gather this information based on a local file path inside my mapped workspace.
Is it somehow possible without using the ExtendedClient?
I want something like this:
TfvcChangesetSearchCriteria tcsc = new TfvcChangesetSearchCriteria();
tcsc.ItemPath = #"c:\source\mappedtfs\MYPROJECT\src\MainWindow.cs";/*<--- localPath would be nice here*/
List<TfvcChangesetRef> changerefs = tfvcHttpClient.GetChangesetsAsync("MYPROJECT", null, null, null, null, tcsc).Result;
Microsoft.Teamfoundation.SourceControl.WebApi is a webapi which does not interact with local workspaces and files. If you want to get changesets with local items' path, use Microsoft.TeamFoundation.VersionControl.Client in the Client Library.
using Microsoft.TeamFoundation.Client;
using System;
using Microsoft.TeamFoundation.SourceControl.WebApi;
using Microsoft.TeamFoundation.VersionControl.Client;
using System.Collections.Generic;
namespace ConsoleX
{
class Program
{
static void Main(string[] args)
{
Uri url = new Uri("https://tfsuri");
TfsTeamProjectCollection ttpc = new TfsTeamProjectCollection(url);
VersionControlServer vcs = ttpc.GetService<VersionControlServer>();
IEnumerable<Changeset> cses = vcs.QueryHistory("Path here could be local path or server path", RecursionType.Full);
foreach (Changeset cs in cses)
{
Console.WriteLine(cs.ChangesetId);
Console.WriteLine(cs.Comment);
}
Console.ReadLine();
}
}
}
I am making a small game in Unity and I'm in need of a database. I tried using SQLite database because that seemed to be recommended by the web.
Now I'm having troubles with actually connecting to the local database via c#.
I implemented the Data in SQLite .dll's.
I am trying to get 1 name from the database that I created using SQLite developer.
Below is my DataConnection class, which I use to connect to the database.
using UnityEngine;
using System.Collections;
using System.Data;
using Mono.Data.SqliteClient;
public class Dataconnection : MonoBehaviour {
private string _constr = #"Data Source=C:\Program Files (x86)\SharpPlus\SqliteDev\GameDatabase.db;Version=3;";
private IDbConnection _dbc;
private IDbCommand _dbcm;
private IDataReader _dbr;
public Dataconnection()
{
}
public Dataconnection(string constring)
{
_constr = constring;
}
public string ExcecuteQuery(string SQL)
{
string output = "";
try
{
_dbc = new SqliteConnection(_constr);
_dbc.Open();
_dbcm = _dbc.CreateCommand();
_dbcm.CommandText = SQL;
_dbr = _dbcm.ExecuteReader();
}
catch
{
}
while (_dbr.Read())
{
output = _dbr.GetString(0);
}
_dbc.Close();
return output;
}
}
Then I call the following method from another class:
datacon.ExcecuteQuery("SELECT name FROM employee WHERE empid = 1;");
I get the following errors when running the code:
So I'm guessing it has something to do with a 32/64 -bit mismatch or is there something wrong with creating an instance of a script like this?:
private Dataconnection datacon;
void Start()
{
datacon = new Dataconnection();
}
Happy to receive any help at all. I'm familiar with using database, just new to SQLite.
It says it cannot load the native sqlite.dll because you have there 64 bit version and it needs 32 bit
Place this in your app folder https://www.sqlite.org/2015/sqlite-dll-win32-x86-3081001.zip
Please fill that empty catch on line 38 with a throw;
as there is an exception hidden there which is the true cause of the null reference.
You could also post your connection string so I could make this answer better.
I got it working now. The problem was my that one of the SQLite .dll's was still 32bit. I did this tutorial over again and searched google for the 64bit .dll files and now it's working.
Need to integrate this PowerShell script into my C# Assembly code. No idea how to do this. If any other information is needed please do not hesitate to ask. Thanks in advance.
PowerShell Script:
#Script that does the linking and renaming:
# Creates a variable called IncidentID and points Incident # to it for use within the script
Param(
[string]$IncidentID
)
# Load the SMlets module
Import-Module SMlets
# Get the Incident Class
$IncClass = Get-SCSMClass -Name System.WorkItem.Incident$
# Get the RMA Class
$RMAClass = Get-SCSMClass -Name COMPANY.RMA.Class
# Build the Filter String
$FilterStr = "ID -eq " + $IncidentID
# Find the Incident we need to link to an RMA
$Inc = Get-SCSMObject -Class $IncClass -Filter $FilterStr
$RMAIncText = "[Linked to Incident " + $Inc.ID + "]"
$RMADescription = $RMAIncText
New-SCSMObject -Class $RMAClass -PropertyHashtable (#{Title = $Inc.Title; Description = $RMADescription})
# Find the new RMA to be linked
$FilterStr = "Description -eq '$RMADescription'"
$RMA = Get-SCSMObject -Class $RMAClass -Filter $FilterStr
#Set RMA Number Variable
$RMANumber = $RMA.RMA_ID;
#Clean up DisplayName, Title and Description
$RMA | Set-SCSMObject -PropertyHashtable #{"DisplayName" = $RMANumber; "Title" = $RMANumber; "Description" = $RMANumber;}
## Create an Incident Related Items instance referencing the new RMA
$RWIClass = Get-SCSMRelationshipClass -Name System.WorkItemRelatesToWorkItem$
New-SCSMRelationshipObject -Relationship $RWIClass -Source $Inc -Target $RMA -Bulk
# Unload the SMlets module
Remove-Module SMlets
Assembly Code:
public class RMATask : ConsoleCommand
{
public RMATask()
{
}
public override void ExecuteCommand(IList<NavigationModelNodeBase> nodes, NavigationModelNodeTask task, ICollection<string> parameters)
{
IManagementGroupSession session = (IManagementGroupSession)FrameworkServices.GetService<IManagementGroupSession>();
EnterpriseManagementGroup emg = session.ManagementGroup;
ManagementPack mp = emg.ManagementPacks.GetManagementPack(new Guid("a82d62c5-ece0-35fd-a266-9afa246dea78"));
ManagementPackClass mpc = emg.EntityTypes.GetClass(new Guid("4b081ab1-f48e-9c62-77bc-76bc31349030"));
ManagementPackObjectTemplate mpt = emg.Templates.GetObjectTemplate(new Guid("92ed7c4d-aff5-819e-90f8-c92064c50cd6"));
NavigationModelNodeBase nodeIn = nodes[0];
NavigationModelNodeBase nmnbNew;
NavigationModelNodeTask nmntNew = NavigationTasksHelper.CreateNewInstanceLink(mpc, mpt);
Microsoft.EnterpriseManagement.GenericForm.GenericCommon.MonitorCreatedForm(nodeIn, nmntNew, out nmnbNew);
}
}
For those interested in the details here they are:
Problem
Basically, we have help desk analysts who generate the incidents. SOMETIMES, they may have a need to generate an RMA (Return Merchandise Authorization, if you don't know what that means, just know that it is another form they need to fill out), and that RMA needs to be associated with an incident. An incident does not REQUIRE to have an RMA, but every RMA needs to be attached to its appropriate parent incident.
To do this I created a new class called COMPANY.RMA.Class, created a new form from scratch in Visual Studio, and packaged the MP (Management Pack) XML and form assembly (.dll) into an MPB (management pack bundle).
I uploaded this to the console, and created a new console task called "Create RMA" that became visible when selecting the incident module.
This task would launch my PowerShell script, which in turn would take the ID of the incident selected or opened, create an RMA object, and associate the RMA object created with the ID # of the Incident (allowing it to be seen later in the "Related Items" Tab of the incident).
However, I ran into a problem here. I create the linking functionality correctly, but I cannot get the RMA form to automatically open up after it is created. Instead, when the task is run, it creates the object and saves it, but the analyst has to close the incident and reopen it to refresh the new data, navigate to the "Related Items" tab, and select the newly created RMA to open it up and fill out the form. This is alot of extra work and should be eliminated.
The correct functionality should be to create the RMA form, associate it with the open/selected incident, and launch the RMA form it just created to allow the analyst to fill in its details.
Apparently there is no function to call/launch the form directly from the console task. It seems I must modify the assembly code directly to be able to access the SCSM SDK (the layer I need to be working in). This is where I am lost - I have no idea how to convert my PowerShell script to C# Assembly code. Any help would be greatly appreciated.
You may use the PowerShell class to host PowerShell in your app.
The host application can define the runspace where commands are run, open sessions on a local or remote computer, and invoke the commands either synchronously or asynchronously based on the needs of the application.
There's guidance here.
I ended up solving this alternatively.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
/// using System.Threading.Tasks; <- .NET 4.5 only
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.EnterpriseManagement;
using Microsoft.EnterpriseManagement.Common;
using Microsoft.EnterpriseManagement.Configuration;
using Microsoft.EnterpriseManagement.ConnectorFramework;
// using Microsoft.EnterpriseManagement.UI.Core;
using Microsoft.EnterpriseManagement.UI.Extensions.Shared;
using Microsoft.EnterpriseManagement.UI.FormsInfra;
using Microsoft.EnterpriseManagement.UI.Core.Connection;
using Microsoft.EnterpriseManagement.UI.DataModel;
using Microsoft.EnterpriseManagement.UI.SdkDataAccess;
using Microsoft.EnterpriseManagement.UI.SdkDataAccess.DataAdapters;
using Microsoft.EnterpriseManagement.UI.WpfWizardFramework;
using Microsoft.EnterpriseManagement.ServiceManager.Application.Common;
using Microsoft.EnterpriseManagement.ConsoleFramework;
using Microsoft.EnterpriseManagement.GenericForm;
// using System.Management.Automation;
[assembly: CLSCompliant(true)]
namespace COMPANY.RMA
{
/// <summary>
/// Interaction logic for UserControl1.xaml
/// </summary>
class RMATask : CreateWithLinkHandler
{
public RMATask()
{
try
{
// Sealed Class GUID
this.createClassGuid = new Guid("9ebd95da-1b16-b9ea-274d-6b0c16ce1bf3");
this.classToDelegate = new Dictionary<Guid, CreateLinkHelperCallback>()
{
{ ApplicationConstants.WorkItemTypeId, new CreateLinkHelperCallback (this.WorkItemCallback) }
};
}
catch (Exception exc1)
{
MessageBox.Show(exc1.Message, "Exception", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
public void WorkItemCallback(IDataItem RMAForm, IDataItem IncidentForm)
{
try
{
// Note to self: RelatedWorkItems should be in MP XML as alias under TypeProjections
if (RMAForm != null && RMAForm.HasProperty("RelatedWorkItems"))
{
// Perform Linking
RMAForm["RelatedWorkItems"] = IncidentForm;
// Copy Incident Title to RMA Title
RMAForm["Title"] = IncidentForm["Title"];
// Copy Incident Description to RMA Description
RMAForm["Description"] = IncidentForm["Description"];
}
}
catch (Exception exc2)
{
MessageBox.Show(exc2.Message, "Exception", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
}
I am using the following code under ASP.NET 4.0 framework to obtain the version of MSI file from a web app:
string strVersion = "";
try
{
Type InstallerType;
WindowsInstaller.Installer installer;
InstallerType = Type.GetTypeFromProgID("WindowsInstaller.Installer");
installer = (WindowsInstaller.Installer)Activator.CreateInstance(InstallerType);
WindowsInstaller.Database db = installer.OpenDatabase(strMSIFilePath, 0);
WindowsInstaller.View dv = db.OpenView("SELECT `Value` FROM `Property` WHERE `Property`='ProductVersion'");
WindowsInstaller.Record record = null;
dv.Execute(record);
record = dv.Fetch();
strVersion = record.get_StringData(1).ToString();
dv.Close();
//db.Commit();
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(dv);
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(db);
}
catch
{
//Failed
strVersion = "";
}
It works fine except that when the code finishes running it holds an internal MSI file handle so when I try to move or rename the MSI file I get the error that the file is still in use. This continues until I actually navigate away from the ASPX page that calls the method above.
My question is, I obviously didn't close some handle or object in the code above. But what could that be?
PS. I'm testing it in a development IDE from VS2010.
EDIT: Edited the code like it should be after Adriano's suggestion. Thanks!
The COM object has not been released (it should be auto-released when it goes out of scope but in .NET this doesn't work really well). Because it does not implement the IDisposable interface you can't call its Dispose() method and you can't use it inside an using statement. You have to explicitly call Marshal.FinalReleaseComObject. For example:
try
{
// Your stuffs
}
finally
{
dv.Close();
Marshal.FinalReleaseComObject(dv);
Marshal.FinalReleaseComObject(db);
}
Moreover note that you do not really need a call to the Commit() method because you didn't make any change but just a query.
FWIW, you should be using Windows Installer XML (WiX) Deployment Tools Foundation (DTF). It's an FOSS project from Microsoft that can be found on CodePlex. It has MSI interop libraries with classes that are very similar to the COM classes but implement IDisosable and use P/Invoke instead of COM behind the scenes. There is even support for Linq to MSI if you want. And the full source code is available.
DTF is the gold standard for MSI interop in a .NET world. Here are two examples:
using System;
using System.Linq;
using Microsoft.Deployment.WindowsInstaller;
using Microsoft.Deployment.WindowsInstaller.Linq;
namespace ConsoleApplication3
{
class Program
{
const string DATABASE_PATH = #"C:\FOO..MSI";
const string SQL_SELECT_PRODUCTVERSION = "SELECT `Value` FROM `Property` WHERE `Property`='ProductVersion'";
static void Main(string[] args)
{
using (Database database = new Database(DATABASE_PATH, DatabaseOpenMode.ReadOnly))
{
Console.WriteLine(database.ExecuteScalar(SQL_SELECT_PRODUCTVERSION).ToString());
}
using (QDatabase database = new QDatabase(DATABASE_PATH, DatabaseOpenMode.ReadOnly))
{
var results = from property in database.Properties where property.Property == "ProductVersion" select property.Value;
Console.WriteLine(results.AsEnumerable<string>().First());
}
}
}
}
try to Dispose the Objects.
dv.Dispose();
db.Dispose();