'Link Table Manager' functionality Programatically using c# - c#

I want to write some custom code to perform the 'Link Table Manager' operation programatically. I have MS-Access database which is currently referencing external data from Excel,MS-Access and SQL server.
Before executing a Macro on my MS-Access database, I want to re-link the external data sources or provide new location of the data-source in case there is change in the location of the data source.
I have a table in MS-Access database which is Linked to an external SQL data source(Test database). Now I want it to be linked to Production Database. I have tried the following code but it is throwing a COM-Exception with error description as 'ODBC--connection to 'EmployeeConnectionForSQL' failed.'
public void performLinkTableMangerOperationForSQL()
{
string CurrentDatabasePath = #"D:\UDTDatabase\InternalDatabase.accdb";
Microsoft.Office.Interop.Access.Dao.DBEngine DAO = new Microsoft.Office.Interop.Access.Dao.DBEngine();
Microsoft.Office.Interop.Access.Dao.Database db;
Microsoft.Office.Interop.Access.Dao.TableDefs dt;
db = DAO.OpenDatabase(CurrentDatabasePath);
dt = db.TableDefs;
// Refreshing link for Sql server external table with DSN.
string sqlSource = #"DATABASE=Employee;";
string DSNName = "EmployeeConnectionForSQL;";
string sqlNewConnectionString = #"ODBC;FileDSN=" + DSNName + sqlSource;
foreach (Microsoft.Office.Interop.Access.Dao.TableDef table in dt)
{
string name = table.Name;
if (table.Name == "dbo_Employees")
{
table.Connect = sqlNewConnectionString;
table.RefreshLink();
}
}
db.Close();
}

That FileDSN is clearly invalid. A FileDSN should point to a .dsn file. If you want to use a normal DSN, use DSN=, not FileDSN=. Since there's an invalid DSN, you can't relink.
I highly recommend you go DSNless, and just use a connection string, but providing a valid FileDSN should work too.

Related

Is it possible to access the PPSONE data with the DI SDK from SAP B1?

I try to write a sowftware so the production can easily confirm the material items.
Now when I want to get a production order by a key, it can't find a PO.
If I do the same thing with business partner, it works.
We use the PPS One addon for the SAP B1, so is there the problem? Is it not possible to access the data from this addon or what have I to change?
SAPbobsCOM.BusinessPartners vBP = connection.company.GetBusinessObject(SAPbobsCOM.BoObjectTypes.oBusinessPartners);
SAPbobsCOM.ProductionOrders vPO = connection.company.GetBusinessObject(SAPbobsCOM.BoObjectTypes.oProductionOrders);
if(vBP.GetByKey("L22437"))
{
WriteLogLine("Name: " + vBP.CardName); // Works, i get the Name!
}
else { WriteLogLine("No matching customer record was found!"); }
if (vPO.GetByKey(anyKey)) // tried a lot of keys, no one worked
{
WriteLogLine(vPO.GetAsXML());
}
else { WriteLogLine("No matching production order record was found!"); }
There is also a weird thing, in the SAP GUI the po are displayed as work orders, but the coresponding table in the db is #PPSONE_PRDORDERS. But it works neither if I change from SAPbobsCOM.ProductionOrders to SAPbobsCOM.WorkOrders.
If I understood, it doesn't matter what the addon does if at least it creates a record in the PO table, if you want to find the records of PO's you have to query the OWOR table, the field to use in the GeyByKey method of PO is the OWOR.DocEntry.
If this is a UserTable with no Object ou can use the object UserTable
UserTable oUst = (UserTable)oCompany.UserTables.Item(YOURTABLE);
if oUst.GetByKey("1") ....
If it is a UserTable with Object you have to look for GenericServices
Dim oGeneralService As SAPbobsCOM.GeneralService
Dim oGeneralData As SAPbobsCOM.GeneralData
Dim oGeneralParams As SAPbobsCOM.GeneralDataParams
Dim sCmp As SAPbobsCOM.CompanyService
sCmp = oCompany.GetCompanyService
'Get a handle to the SM_MOR UDO
oGeneralService = sCmp.GetGeneralService("SM_MOR")
'Get UDO record
oGeneralParams = oGeneralService.GetDataInterface(SAPbobsCOM.GeneralServiceDataInterfaces.gsGeneralDataParams)
oGeneralParams.SetProperty("DocEntry", "2")
oGeneralData = oGeneralService.GetByParams(oGeneralParams)
There is a SDK from PPS One you can use. Refere to: C:\Program Files\SAP\SAP Business One\AddOns\PPSOne\PPSOne\X64Client\PPSOne_PPSOneSDK.dll. I don't test it.

MVC inject DataAccessLayer based on the logged in user

I've an application which insert/save data in different databases hosted on different server. UI may be different but at the end data which is getting saved is almost same.
So i want to use the same DataAccessLayer but want to change the connectionString based on the loggedin user.
Dependency can be configured in startup.cs but at that time i may not know the DataBase user would like to work with.
on login page i'm asking user to select the database to work with, so only way to change the connection string is after login page.
Any suggestion?
public class ConnectionRepository : IConnectionRepository
{
private IDbConnection _cnn = null;
public IDbConnection GetOpenConnection(string databaseName)
{
if (_cnn != null && _cnn.ConnectionString.ToLower().Contains(databaseName.ToLower()))
{
_cnn.Open();
return _cnn;
}
var cnn = ConfigurationManager.ConnectionStrings["DefaultConnection"].ToString();
//Now replace database name in connection string with whichever one supplied
var cb = new SqlConnectionStringBuilder(cnn) { InitialCatalog = databaseName };
// wrap the connection with a profiling connection that tracks timings
return new ProfiledDbConnection(new SqlConnection(cb.ConnectionString), MiniProfiler.Current);
}
}
This code replaces the InitialCatalog (database name) part of the connection string dynamically base on the supplied name. The current name is stored in session when the user logs in.
Hope this helps.

Managed Entity Framework not generating stored procedures mappings

Please note that I am attempting to use stored procedures to insert and update table records. When I add the stored procedure to the database and update the *.edmx file, it sees the stored procedure I've added; however, I previously did the following with a different project:
var db = new MyMarinaEntities();
db.prBoatInsert(registrationNumber, manufacturer, modelYear, length, customerID);
Now, however, when I type "db." intellisense doesn't see the insert stored procedures. Also, when I search in the InlandMarinaEntities.Designer.cs file, it doesn't have any
public int prBoatUpdate(Nullable<global::System.Int32> boatID, global::System.String registrationNumber, global::System.String manufacturer, Nullable<global::System.Int32> modelYear, Nullable<global::System.Int32> length, Nullable<global::System.Int32> customerID)
function. Does anyone have any idea as to why it is not adding prBoatUpdate to the *.Designer.cs file?
Alternatively, I understand that MEF can generate Insert, Update and Delete operations for each table; however, when I generate the *.edmx file, I don't see any of these operations added, and I don't see any option to add them when going through the wizard to generate the *.edmx file. What am I missing? Please note that I am using Visual Studio 2010 and SQL Server 2008. TIA.
Please note that I determined how to add and update database items using the MEF auto-generated functions instead of using stored procedures. Here is how you load an object from the database:
private void LoadBoat(int boatID)
{
using (var db = new MyMarinaEntities())
{
var boat = db.Boats.SingleOrDefault(b => (b.BoatID == boatID));
this.chkIsRental.Checked = boat.IsRental;
this.chkInactive.Checked = boat.Inactive;
this.txtLength.Text = boat.Length;
this.txtManufacturer = boat.Manufacturer;
// ...
}
}
Here is how to save changes to the boat:
protected void btnSave_click(object sender, EventArgs args)
{
using (var dm = new MyMarinaEntities())
{
MyMarinaEntities boat;
boat.IsRental = this.chkIsRental.Checked;
boat.Inactive = this.chkInactive.Checked;
boat.Length = this.txtLength.Text;
boat.Manufacturer = this.txtManufacturer;
// ...
if (boatID.Value == "")
dm.AddObject("Boats", boat);
dm.SaveChanges();
}
}
So MEF not only saves you from writing lots of code for Object Relational Mapping (ORM), it also saves you from writing SQL code for stored procedures or commands.

Need C# code for reading multiple attachments from Microsoft Access Attachment data type using DataReader

I have multiple documents stored in Attachment data type in Access database. Using DataReader, I need to read multiple attachments along with their file name and store them on the file system. Will appreciate your help...
I had a similar problem, here's how I solved it using DAO.
var dbe = new DBEngine();
Database db = dbe.OpenDatabase(#"C:\tmp\access database file.accdb");
try
{
Recordset rstMain = db.OpenRecordset(
"SELECT `Attachment` FROM `table name`",
RecordsetTypeEnum.dbOpenDynaset);
while (!rstMain.EOF)
{
Recordset2 rstAttach = rstMain.Fields["Attachment"].Value;
rstAttach.OpenRecordset();
while (!rstAttach.EOF)
{
Field2 fldAttach = (Field2)rstAttach.Fields["FileData"];
string fileName = rstAttach.Fields["FileName"].Value.ToString();
fldAttach.SaveToFile(#"C:\tmp\" + fileName);
rstAttach.MoveNext();
}
rstAttach.Close();
rstMain.MoveNext();
}
rstMain.Close();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
You should include using Microsoft.Office.Interop.Access.Dao; in the header.
The only data you get over ADO.NET is semi-colon delimited list of attached files' names. Moreover, you will see that ADO.NET recognizes that column type as String. So, there is no way you would get the actual binary data from the column (on the .NET side).
I would suggest you not using Attachment as data type in Access if you need to access the data from that column outside of Access database. Just create separate table to store all the attachments [links].

Best practice to create (on demand) SQL Server 2008 Express databases in C#?

The purpose is to handle the user's data (you can call them project, document, file, or whatever) in a brand new SQL Server 2008 Express database. The data are expected to occupy much less space than the 4GB available with the express edition (which is also free to distribute).
E.g., each time the user selects File->New command, a new empty database will be created at the specified location. On the other hand, a similar command, File->Open must provide support to retrieve the list of the databases to select one for opening.
So, the following issues must be resolved:
a) The application must be able to create the connection string and attach the database to SQL Server 2008 Express through code (C#)
b) The application must be able to retrieve (again through code) a list with all the available databases, to give the user a chance to select one to open.
I think it would be helpful to have a template database in resources and copy it in the location specified by the user.
Do you think it is a working solution? Do you have any suggestions?
There's lots you can do with Sql Server Management Objects (SMO):
// Add a reference to Microsoft.SqlServer.Smo
// Add a reference to Microsoft.SqlServer.ConnectionInfo
// Add a reference to Microsoft.SqlServer.SqlEnum
using Microsoft.SqlServer.Management.Smo;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Data;
public class SqlServerController
{
private Server m_server = null;
public SqlServerController(string server)
{
m_server = new Server(server);
}
public void AttachDatabase(string database, StringCollection files,
AttachOptions options)
{
m_server.AttachDatabase(database, files, options);
}
public void AddBackupDevice(string name)
{
BackupDevice device = new BackupDevice(m_server, name);
m_server.BackupDevices.Add(device);
}
public string GetServerVersion(string serverName)
{
return m_server.PingSqlServerVersion(serverName).ToString();
}
public int CountActiveConnections(string database)
{
return m_server.GetActiveDBConnectionCount(database);
}
public void DeleteDatabase(string database)
{
m_server.KillDatabase(database);
}
public void DetachDatabase(string database, bool updateStatistics,
bool removeFullTextIndex)
{
m_server.DetachDatabase(database, updateStatistics, removeFullTextIndex);
}
public void CreateDatabase(string database)
{
Database db = new Database(m_server, database);
db.Create();
}
public void CreateTable(string database, string table,
List<Column> columnList, List<Index> indexList)
{
Database db = m_server.Databases[database];
Table newTable = new Table(db, table);
foreach (Column column in columnList)
newTable.Columns.Add(column);
if (indexList != null)
{
foreach (Index index in indexList)
newTable.Indexes.Add(index);
}
newTable.Create();
}
public Column CreateColumn(string name, DataType type, string #default,
bool isIdentity, bool nullable)
{
Column column = new Column();
column.DataType = type;
column.Default = #default;
column.Identity = isIdentity;
column.Nullable = nullable;
return column;
}
public Index CreateIndex(string name, bool isClustered, IndexKeyType type,
string[] columnNameList)
{
Index index = new Index();
index.Name = name;
index.IndexKeyType = type;
index.IsClustered = isClustered;
foreach (string columnName in columnNameList)
index.IndexedColumns.Add(new IndexedColumn(index, columnName));
return index;
}
}
An alternate solution is to use SQLite rather than SQL Express. You can even continue to use ADO.NET if you use this solution. SQLite databases are simply files, and your connection strings can refer to the file path. When a user wants to open their file, they can select an actual file.
I get the impression that this database will live locally on user's machine. If that's the case, sql server express is not usually a good database choice. It's a server-class engine rather than a desktop or in process engine. Instead, there are a number of good in process engines you can use: Sql Server Compact Edition, Sqlite (as mentioned by Jacob) or even Access.
If you believe SQL Server Express 2008 is the right choice (sqllite does seem to fit better though), I would look at using User Instances which will allow non-administrators to add databases from files as you describe.
This article shows how to create a new database, and attach it to a SQL Server database instance:
How to: Attach a Database File to SQL Server Express
http://msdn.microsoft.com/en-us/library/ms165673.aspx
These article shows how to manage the attaching and detaching of existing databases:
http://msdn.microsoft.com/en-us/library/ms190794.aspx
http://www.databasejournal.com/features/mssql/article.php/2224361/Attaching-and-Detaching-Databases-on-SQL-Server.htm
For the following connection string for SQL Server 2008 R2.
<connectionstring>Data Source=.\SQLEXPRESS;Initial Catalog=MyDatabase;Integrated Security=True;Pooling=True</connectionstring>
you can do
var connectionString = new SqlConnectionStringBuilder(connectionString);
var serverConnection = new ServerConnection("DatabaseInstanceName in server");
var serverInstance = new Server(serverConnection);
if (serverInstance.Databases.Contains(connectionString.InitialCatalog))
serverInstance.KillDatabase(connectionString.InitialCatalog);
var db = new Database(serverInstance, connectionString.InitialCatalog);
try
{
db.Create();
}
catch (SqlException ex)
{
throw;
}
Thanks to Mr. Harvey for pointing the right direction. Although in my case, I have to make these small changes. Because, I use the windows authentication.

Categories