I'm working with VB.Net and Oracle 11g connecting thru ODAC to build a desktop application, it should be pretty simple but I'm facing a situation.
I have my security roles and users defined on the Oracle Database, my intent is to show menus according to each role (i.e administrator should see every menu while user only the relevant menus) my question is how can this be accomplished?
I was creating a separate table with usernames and roles but I bet there's a better way for handling this. Willing to take all suggestions at this point
You can use function DBMS_SESSION.IS_ROLE_ENABLED to get this information.
PL/SQL part would be like this
CREATE OR REPLACE FUNCTION IsRoleGranted(RoleName IN VARCHAR2) RETURN Integer IS
BEGIN
IF DBMS_SESSION.IS_ROLE_ENABLED(RoleName) THEN
RETURN 1;
ELSE
RETURN 0;
END IF;
END IsRoleGranted;
In VB.NET you an call the function like this:
Dim cmd As OracleCommand
Dim con As OracleConnection
con = New ...
cmd = New OracleCommand("BEGIN IsRoleGranted(:role); END;" con)
cmd.CommandType = CommandType.Text
cmd.Parameters.Add("res", OracleDbType.Byte, ParameterDirection.ReturnValue)
cmd.Parameters("res").DbType = DbType.Byte
cmd.Parameters.Add("role", OracleDbType.Varchar2, ParameterDirection.Input).Value = "MYAPP_ADMIN"
cmd.ExecuteNonQuery()
AdminMenu.Visible = CByte(cmd.Parameters("res").Value) = 1
DBMS_SESSION.IS_ROLE_ENABLED is easier to use than query view SESSION_ROLES because it also covers hierarchy of roles, i.e. when a role is granted to another role.
Filling a table in Oracle with the active directory roles and users is an often used solution.
Oracle has a DBMS_LDAP package to access Active Directory so you can get a list of groups for your app. I suggest a prefix for roles used in your app such as MyApp_admin, MyApp_user.
Then run a scheduled job to get the users that are in the groups and fill it into
something like this pseudo code table
TABLE GROUP_USER (
ID NUMBER(9) primary key,
GROUP_NAME VARCHAR2(250),
USER_NAME VARCHAR2(250));
This puts security at the enterprise level
allows the possibility of single sign on using sys_context('USERENV','OS_USER')
Related
I am working with Unidata, and ADO.NET using the U2 .NET Provider. This may be a shot in the dark as there are not many resources for Unidata and .NET these days.
Currently I can only return a single MV record 153926þIþ and parse it using MV_To_DataTable. I'd like to return multiple records like 153926þIþÿ153926þIþÿ. Is there any built in mechanism for doing this? I fear I will have to write the extension to best accomodate me.
I retrieve a single record in a unidata subroutine this way:
SUBROUTINE GETITEMS(results)
EXECUTESQL "SELECT ID, STATUS, DESC FROM ITEMS TO GETITEM_LIST;"
DONE = 0
RECCNT = 0
LOOP
RECCNT += 1
READNEXTTUPLE REC FROM "GETITEM_LIST" ELSE DONE = 1
results := REC
IF RECCNT EQ 1 THEN EXIT
UNTIL DONE
REPEAT
results
CLEARSQL
RETURN
Simple subroutine that returns one record without any record marks. This works when I use the U2Parameter method called MV_To_DataTable to parse it into an existing datatable.
However when I change the subroutine line:
results:= REC to results:= REC : #RM to append the record marks and remove the limit of 1, the MV_To_DataTable no longer is able to parse it correctly. In fact it will throw System.IndexOutOfRangeException: Cannot find column 3.
VB.NET Code:
' ... Open database connection called U2Connection ...
Dim cmd = U2Connection.CreateCommand
cmd.CommandText = "CALL GETITEMS(?)"
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.Clear()
cmd.Parameters.Add(New U2Parameter("#arg1", "") With {.Direction = ParameterDirection.InputOutput})
cmd.ExecuteNonQuery()
Dim tb As New DataTable
tb.Columns.Add("ID")
tb.Columns.Add("STATUS")
tb.Columns.Add("DESC")
cmd.Parameters.Item(0).MV_To_DataTable(tb) ' Error happens here
' System.IndexOutOfRangeException: Cannot find column 3.
It appears the method does not separate records. I could be interpretting this incorrectly.
*****UPDATE 2/9/2019
I went ahead and wrote my own extension method to support my return format with the record markers. It populates a datatable with records allowing me to continue as I normally would.
You are kind of straddling the Multivalue/System.Data divide here. If you have not already done so, I would suggest looking into the U2 Toolkit for .NET, which I believe is generally readily available if you are current on maintenance. It comes with some samples of how to do things like this in C# and VB as well some Entity Framework stuff.
But as to what is going on here, You are trying to put a U2Type.DynArray into a System.DataTable is kind of tricky as the DynArray is a Record state, which could contain multiple rows from multiple tables within a DataSet. As #RM is the terminator for a record so it turns DynArray into DynArray[] and you can't have that as a parameter as such.
To fix this with the minimum refactoring, you can still use MV_To_DataTable, but note that it is expecting your data to be tabular and in in a single record. These example assume a newline is an Attribute mark (#FM/#AM)
Here is the contents of what you are returning
Row1Column1
Row1Column2
Row1Column3:#RM
Row2Column1
Row2Column2
Row2Column3:#RM
Row13olumn1
Row13olumn2
Row13olumn3:#RM
And here is what MV_To_DataTable expects
Row1Column1:#VM:Row1Column2:#VM:Row1Column3
Row2Column1:#VM:Row2Column2:#VM:Row2Column3
Row3Column1:#VM:Row3Column2:#VM:Row3Column3
If you adjust your U2 sub to output that, it should work.
Additionally, you could try using your SQL command directly for .net, but that becomes perilous for other reasons depending on your data.
Good Luck!
Hello guys i building a web app with asp.net and using sql ( MS SQL server 2000 ) and now after getting closer to finish i noticed that the sql part of my code taking huge amounts of space... and i was wondering what ways are there to make it easier to maintain? maybe even change to some other language?
Here is a simple example of the way my sql code is built ( there are some much longer commands in my code but they built this way) :
Dim connectionString As String = ConfigurationManager.ConnectionStrings("ConnectionString").ToString()
Dim query As String = "SELECT workerName FROM [poWorker] WHERE ( companyId = #companyId ) AND (workerId=#workerId) "
Using con As New SqlConnection(connectionString)
con.Open()
Using da As New SqlDataAdapter()
Using command As New SqlCommand(query, con)
command.Parameters.Add(New SqlParameter("#workerId", Session("userId")))
command.Parameters.Add(New SqlParameter("#companyId", Session("companyId")))
Dim ds As New DataSet()
da.SelectCommand = command
da.Fill(ds, "test")
If ds.Tables(0).Rows.Count = 1 Then
managerName = ds.Tables(0).Rows(0)(0).ToString()
End If
End Using
End Using
con.Close()
End Using
This is taking a lot of space and i got a lot of sql written this way. I am sure there is some solution in making it easier to maintain, probably using a newer technology? Maybe if i could figure out a way to call all the sql commands from 1-2 functions but so far i failed to do such a thing since there big differences between many of those.
In the example you give, you could simplify the code by using ExecuteScalar - as you are just returning a single value. For example:
Dim query As String = "SELECT workerName FROM [poWorker] WHERE ( companyId = #companyId ) AND (workerId=#workerId) "
Using con As New SqlConnection(connectionString)
con.Open()
Using command As New SqlCommand(query, con)
command.Parameters.Add(New SqlParameter("#workerId", Session("userId")))
command.Parameters.Add(New SqlParameter("#companyId", Session("companyId")))
managerName = command.ExecuteScalar().ToString();
End Using
con.Close()
End Using
A modern way to access databases from code is to use an ORM. The one that Microsoft provides with the .NET Framework is Entity Framework. This allows you to write your query like this:
Dim worker as Worker =
dbContext.Workers
.Where(Function (w) (w.companyId = Session("companyId") and
w.workerId = Session("userId")))
.SingleOrDefault()
If worker IsNot Nothing Then
managerName = worker.workerName
End If
This approach also provides a far more robust approach to dynamic queries as opposed to piecing SQL strings together. For example, you can dynamically swap out Where clauses, OrderBy clauses, and so on, and still have completely typesafe code.
Entity Framework does not have builtin support for SQL Server 2000, but apparently there is a workaround.
The modern way is to no use SQL directly, but rather an OR-Mapper such as Entity Framework that allows you to query using Linq.
The query you show above would the be reduced to something shorter:
using(new context = MyAppDbContext())
{
var workerId = Session["userId"];
var companyId = Session["companyId"];
managerName = context.PoWorker
.Single(w => w.companyId == companyId && w.workerId == workerId)
.workerName;
}
Sorry for using C# syntax, but I hope you can figure out the intention.
I currently have a site (.net 2.0) with MS Access DB for data, within the access.mdb are 2 linked tables from another DB on the same site. - all of my code works fine and all my DB connections point to the one DB. I have a need now to achieve the same results, but don't want to create the links in the live DB. How can the same results be achieved via another method?
I looked at an example from: Syntax for Import Into from Different DBs - MS Access
My tables are large and don't think this is fastest way, I would think two connections and working with tables would be better, but I'm open to a proper way to accomplish this.
Here is my web.conf file with connections to the one DB.
<connectionStrings>
<clear />
<add name="OdbcServices" connectionString="Driver={Microsoft Access Driver (*.mdb)};Dbq=e:\LeaveDB.mdb;" />
</connectionStrings>
My end result I need to join 2 tables from different DB's something like:
SELECT username.table1, password.table1, fullname.table2 FROM Table1 INNER JOIN [;DATABASE=Z:\Docs\Test.mdb].Table2 ON username.table1 = username.table2;
Rather than create an "official" linked table (TableDef object) you might get away with simply creating a View that points to the table in the other database. I just tried this in C# and it seemed to work fine:
string myConnectionString;
myConnectionString =
#"Provider=Microsoft.ACE.OLEDB.12.0;" +
#"Data Source=C:\Users\Public\Database1.accdb;";
using (var con = new OleDbConnection())
{
con.ConnectionString = myConnectionString;
con.Open();
using (var cmd = new OleDbCommand())
{
cmd.Connection = con;
cmd.CommandType = System.Data.CommandType.Text;
cmd.CommandText =
#"CREATE VIEW otherTable AS " +
#"SELECT * FROM [;Database=C:\__tmp\main.accdb].otherTable";
cmd.ExecuteNonQuery();
}
con.Close();
}
That creates a "View" (saved query in Access) that seems to work just like a linked table.
SQL Server 2005. Visual Studio 2010. ASP.NET 2.0 Web Application
This is a web application that supports multiple languages, one of them is Korean. I have “langid” in the query string to differentiate different languages, if langid=3 it is Korean.
In my code behind’ C# code, I read a table using this query:
"select * from Reservations where rsv_id = 1234"
There is a column named "rsv_date" in the table which is reservation date, of type datetime. In the db table its value is "11/22/2012 4:14:37 PM". I checked this in SQL server management studio. But when I read it out, I got "2012-11-22 오후 4:14:37"! Where does that Korean “오후” come from??? Is it because of some culture setting anywhere? But I don’t see where, either in my code or in SQL Server. This caused problem for me, because when I modify this record, it will try to write "2012-11-22 오후 4:14:37" to the db, which of course SQL server reports error.
My original code:
Hashtable reservation = new Hashtable();
SqlCommand sqlCommand = null;
SqlDataReader dataReader;
string queryCommand = "select * from Reservations where rsv_id = #RsvID";
sqlCommand = new SqlCommand(queryCommand, getConnection());
sqlCommand.Connection.Open();
sqlCommand.Parameters.AddWithValue("#RsvID", rsvID);
dataReader = sqlCommand.ExecuteReader();
while (dataReader.Read())
{
reservation["rsvID"] = dataReader["rsv_id"];
reservation["rsvCode"] = dataReader["rsv_code"];
reservation["rsvType"] = dataReader["rsv_type"];
reservation["rsvDate"] = dataReader["rsv_date"]; // where does Korean come from?
...
}
It's a common misunderstanding that you can "check" the format of datetime fields in the database.
The format you see on screen will always depend on the client, even if the client is "SQL server management studio".
In the database, the datetime is stored in a binary format that very few need to know.
So, the Korean characters are from the client, in this case your own program.
And Yes, they will depend on some culture setting somewhere.
Your example doesn't show what happens to reservation["rsvDate"] , where is the value displayed with the Korean characters ?
How are you trying to write the value with Korean characters to the database ?
To avoid Korean characters you could use .ToString(CultureInfo.InvariantCulture) where you use the Date value.
I basically need to know how to import SQL code into Access. I've tried one way but that requires me to do one table and one value at a time which takes a lot of time.
Can anyone help?
If you are trying to import data, rather than SQL code (see Duffymo's response), there are two ways.
One is to go where the data is and dump a .CSV file and import that, as Duffymo responded.
The other is to create a table link from the Access database to a table in the source database. If the two databases will talk to each other this way, you can use the data in the remote table as if it were in the Access database.
Well, some days ago I needed to shift data from an Access database to SQL (reverse of what you're doing). I found it simpler to write a simple script that would read data from my access database and insert it into SQL.
I don't think doing what you need to do is any different.
I don't know if it will help, but I posting my code (It's a simple C# function). You can just change the connections and it will work. Of course I only had 3 fields so I hard-coded them. You can do the same for your db schema.
protected void btnProcess_Click(object sender, EventArgs e)
{
//Open the connections to the access and SQL databases
string sqlDBCnn = #"Data Source=.\SQLEXPRESS;Integrated Security=True;AttachDBFileName=|DataDirectory|\mydb.mdf;user instance=true";
string accessDBCnn = #"Provider=Microsoft.Jet.OleDB.4.0;Data Source=C:\mydb.mdb";
OleDbConnection cnnAcc = new OleDbConnection(accessDBCnn);
cnnAcc.Open();
SqlConnection cnnSql = new SqlConnection(sqlDBCnn);
cnnSql.Open();
SqlCommand cmSql = new SqlCommand("DELETE tablename", cnnSql);
cmSql.ExecuteNonQuery();
//Retrieve the data from the Access Database
OleDbCommand cmdAcc = new OleDbCommand("SELECT * FROM tablename", cnnAcc);
OleDbDataReader drAcc = cmdAcc.ExecuteReader();
using (drAcc)
{
if (drAcc.HasRows)
{
//Loop through the access database records and add them to the database
while (drAcc.Read())
{
SqlCommand cmdSql = new SqlCommand("INSERT INTO tablename(Category, Head, Val) VALUES(#cat,#head,#val)",cnnSql);
SqlParameter parCat = new SqlParameter("cat",System.Data.SqlDbType.VarChar,150);
SqlParameter parHead = new SqlParameter("head",System.Data.SqlDbType.VarChar,150);
SqlParameter parVal = new SqlParameter("val",System.Data.SqlDbType.VarChar);
parCat.Value = drAcc["Category"].ToString();
parHead.Value = drAcc["Head"].ToString();
parVal.Value = drAcc["Val"].ToString();
cmdSql.Parameters.Add(parCat);
cmdSql.Parameters.Add(parHead);
cmdSql.Parameters.Add(parVal);
cmdSql.ExecuteNonQuery();
}
}
}
lblMsg.Text = "<p /> All Done Kapitone!";
}
SQL code? Or data? "one table and one value" makes me think it's the latter. If so, I'd suggest dumping the data out into a .csv file and importing that into Access tables.
Or maybe using a tool like Microsoft's DTS to map and move the data between sources. That would be the best idea.
I guess you are talking about "importing" both structure and data from SQL to ACCESS. ACCESS does not accept standard TSQL scripts that you could generate directly from your SQL Database. There are some commercial products like EMS that can more or less do the job for you. EMS has a data exporter module that can take your SQL data in different formats, including Access.
Another way would be to open an Access file and write some basic VBA code, taking advantage of the DoCmd.TransferDatabase method, where you can link OR copy tables from other databases into Access.
I forgot if these methods also allow the transfer of a 'clean' database model, including primary keys and relations... You'll have to give it a try.