LINQ generates incomplete query - c#

so i have this query
var pac = from p in context.pacientebi where p.personalid == piradinomeri select p;
it generates this sql
SELECT
[Extent1].[id] AS [id],
[Extent1].[name] AS [name],
[Extent1].[surname] AS [surname],
[Extent1].[dateofbirth] AS [dateofbirth],
[Extent1].[personalid] AS [personalid],
[Extent1].[phonenumber] AS [phonenumber],
[Extent1].[sqesi] AS [sqesi],
[Extent1].[address] AS [address],
[Extent1].[shemosvlisdro] AS [shemosvlisdro],
[Extent1].[email] AS [email]
FROM [dbo].[pacientis] AS [Extent1]
WHERE ([Extent1].[personalid] = #p__linq__0) OR (([Extent1].[personalid] IS NULL) AND (#p__linq__0 IS NULL))
and doesn't return any value, if i change table name to include database name
like this
FROM [dbo].[pacientis]
to this
[CachedeskBase].[dbo].[pacientis]
everything is fine.
so why does linq to slq generate incomplete query?

I have an idea of what might be causing your problem;
You should check that your current Connection String contains a default catalogue parameter and possibly make sure that your application's database user default database is set.
Setting The initial catalogue/database variable in the connection string:
You might have miss typed or forgot to include a default catalogue/database in your connection string.
Including the default catalogue in your connection string tells your database server which database to use for your requests. (In this case, your LINQ/entity framework requests.)
Here is an example of a connection string containing a default catalogue:
data source=[Your server's address];initial catalog=[Your database CachedeskBase in your case];persist security info=[set to false if you plan on using sql authentification, else true];user id=[Your default user];password=[your user's password];MultipleActiveResultSets=True;App=EntityFramework
Side note: in a production or even development environment you shouldn't include plain database usernames and passwords. I would recommend you look into ISS App Pools if you are planning on deploying this application. When using an app pool you do not specify a user for your application and therefore their passwords. The user id and password fields are replaced by integrated security tag
Setting the application's database user default database:
This action is not recommended as you should always have a default catalogue/database for your user that doesn't contain any potentially dangerous data. This is mostly for security as you want to add hurdles in the path of potential intruders. Making your application's database your user's default database should not be something you want to happen.
As I have a SQL server instance running, I'll be using SQL Server for my example.
In SQL Server Management Studio, go to the security folder and then in the logins folder of the object editor for your database and double click on your user. (If you are using IIS app pools, look for IIS APPPOOL\[your app pool name]).
This should open the login properties window, allowing you to set the default database of your user.

You might need to specify your connectionstring to the datacontext as asked here.
Dim connectionString = "Data Source=myserver;Initial Catalog=mydatabasename;Integrated Security=True"
Using ctx As New HRManagerDataContext(connectionString))
Return (From us As User In ctx.Users
Where us.IsActive = True
Select us)
End Using

Related

SQL Server 2012 & .NET suser_sname() returns different values dependent on accessed from Local IIS or Remote IIS

I'm having an issue with returning the desired username into SQL Server as a default value for a table. All was working well while I was working on my local machine and the remote SQL Server. When I deployed my project this week, I found that my SQL Server 2012 triggers were returning the server name of the IIS server (IIS01) instead of returning the desired value, the username of the user running the web application.
The following table is written to by UPDATE and INSERT triggers for another table. The table design is this:
CREATE TABLE [dbo].[table]
(
[id] [int] NOT NULL,
[username] [varchar](50) NULL,
[dt_changed] [smalldatetime] NULL,
[actiontype] [char](1) NULL
)
GO
ALTER TABLE [dbo].[table]
ADD CONSTRAINT [DF_table_username] DEFAULT suser_sname()) FOR [username]
GO
ALTER TABLE [dbo].[table]
ADD CONSTRAINT [DF_table_dt_changed] DEFAULT (getdate()) FOR [dt_changed]
GO
When I write to the triggered table via .NET running on IIS Express Visual Studio, it inserts the correct username into the table,
id username dt_changed actiontype
534 domain\drewl 2017-11-07 13:39:00 I
When I write to the triggered table from .NET running on IIS on a remote IIS01 server, it inserts an incorrect username into the table. The username inserted is the servername of the domain.
id username dt_changed actiontype
533 domain\IIS01$ 2017-11-07 11:16:00 I
In .NET, I am using a couple different ways of getting the username of the user running the script,
System.Web.HttpContext.Current.User.Identity.Name
<asp:LoginName runat="server" />
Both of these return the correct user on both the local IIS Express and the remote IIS01 IIS server.
In order to rule out that I was not using the wrong SQL command for the username, I wrote this bit of C# to show me the values for each.
string ResourceLoginName = Convert.ToString(System.Web.HttpContext.Current.User.Identity.Name);
string UsernameOnly = ResourceLoginName.Split('\\')[1];
detectedusername.InnerHtml = UsernameOnly;
SqlConnection con = new SqlConnection();
con.ConnectionString = ConfigurationManager.ConnectionStrings["RMConnectionString"].ConnectionString;
con.Open();
SqlCommand cmd = new SqlCommand("SELECT 'ORIGINAL_LOGIN()' AS UserFunction, ORIGINAL_LOGIN() AS UserValue UNION SELECT 'SUSER_NAME(SUSER_ID())' AS UserFunction, SUSER_NAME(SUSER_ID()) AS UserValue UNION SELECT 'SUSER_SNAME(SUSER_SID())' AS UserFunction,SUSER_SNAME(SUSER_SID()) AS UserValue UNION SELECT 'SYSTEM_USER' AS UserFunction,SYSTEM_USER AS UserValue UNION SELECT 'CURRENT_USER' AS UserFunction,CURRENT_USER AS UserValue UNION SELECT 'USER_NAME(USER_ID())' AS UserFunction,USER_NAME(USER_ID()) AS UserValue UNION SELECT 'SESSION_USER' AS UserFunction,SESSION_USER AS UserValue UNION SELECT 'USER' AS UserFunction,USER AS UserValue", con);
cmd.CommandType = CommandType.Text;
SqlDataAdapter da = new SqlDataAdapter(cmd);
DataTable dt = new DataTable();
da.Fill(dt);
Users.DataSource = dt;
Users.DataBind();
As above, the IIS Express returns the correct usernames,
.NET
drewl
SQL
Function Value
CURRENT_USER dbo
ORIGINAL_LOGIN() MTROGERS\drewl
SESSION_USER dbo
SUSER_NAME(SUSER_ID()) MTROGERS\drewl
SUSER_SNAME(SUSER_SID()) MTROGERS\drewl
SYSTEM_USER MTROGERS\drewl
USER dbo
USER_NAME(USER_ID()) dbo
While the remote IIS01 IIS server returns,
.NET
drewl
SQL
Function Value
CURRENT_USER domain\IIS01$
ORIGINAL_LOGIN() domain\IIS01$
SESSION_USER domain\IIS01$
SUSER_NAME(SUSER_ID()) domain\IIS01$
SUSER_SNAME(SUSER_SID()) domain\IIS01$
SYSTEM_USER domain\IIS01$
USER domain\IIS01$
USER_NAME(USER_ID()) domain\IIS01$
What am I missing here and how can I get it to work in the remote (PROD) IIS like it does in IIS Express?
After some more head scratching and research, I found this Stack Overflow question\answer,
I changed my WebConfig to use impersonation,
<identity impersonate="true" />
Set the AppPool to Classic mode (from Integrated), then followed Mike Pollitt's answer, to use Basic Authentication instead of Windows Authentication.
In IIS, only Basic Authentication logs users on with a security token that flows across the network to a remote SQL server. By default, other IIS security modes used in conjunction with the identity configuration element settings will not result in a token that can authenticate to a remote SQL Server.In IIS, only Basic Authentication logs users on with a security token that flows across the network to a remote SQL server. By default, other IIS security modes used in conjunction with the identity configuration element settings will not result in a token that can authenticate to a remote SQL Server.
Once I changed this and restarted the website in IIS, it now returns the correct username.

How do you connect from ODP.NET to Oracle (12G+) by proxy user with no password

There seems to be no answer online as to how you can use Oracle Data Provider for .NET (ODP.NET) to connect to Oracle (12G and later) in a very specific scenario:
User is identified externally on a database
User is granted access to another schema (application user) by proxy connect
User has been set up like this:
CREATE USER user_in_question
IDENTIFIED EXTERNALLY
-- etc.
And connect by proxy has been set up like this:
ALTER USER specified_app_user GRANT CONNECT THROUGH user_in_question
The logical approach when creating the ODP.NET OracleConnection string would be something like this (using the user friendly OracleConnectionStringBuilder):
var connBuilder = new OracleConnectionStringBuilder
{
UserID = "/", // External login using the user running the program
ProxyUserId = "specified_app_user",
DataSource = "database",
};
This does not work. Nor does providing blank "Password" or blank "Proxy Password". Nor does removing the UserId.
So how do you connect using ODP.NET in these circumstances?
The answer (which I spend an hour searching for without any luck) is actually really simple, yet not very user friendly:
var connBuilder = new OracleConnectionStringBuilder
{
UserID = "[specified_app_user]",
DataSource = "database",
};
//connBuilder.ToString() output:
//"USER ID=[specified_app_user];DATA SOURCE=database"
This works in .NET 4.5+ on Oracle 12G+, but probably also on earlier platforms of .NET/Oracle/ODP.NET. I did not test it in ASP.NET, but it should work there too.
This way the UserId actually functions just like the ProxyUserId, just enclosed within brackets, just as you would normally log in on the Oracle Database using, say, Toad or SQlPlus.
It might also be possible using this format (but in my case the connection string had to be compatible with the OraOLEDB format so that did not work):
//Without the use of the conn string builder class, just for the fun of it...
var connString = "User Id=specified_app_user;Data Source=database;Proxy User Id=/";
EDITED 2nd March 2017: The line above does not seem to work in certain cases. Added comment about it and here is the code that IS working:
USER ID=[specified_app_user];DATA SOURCE=database
This info does not seem to exist anywhere - else I overlooked it, and in that case PLEASE do correct me.

SqlDependency not updating cache

I'm on a project using .NET 4.5, MVC, EF 6
I had naively implemented a caching system using the HttpRuntime cache and needed to invalidate the data I cache on updates to that data; except I forgot to take into account that our production server is published to a load balanced set of two servers... :|
So on production, after the data was updated, the app would sometimes serve the right data, and sometimes the old data depending on which server the request was hitting. Bad news bears.
So I decided to define a dependency on the SQL table AcademicTerms which is where my data is coming from. But I did something wrong, and I'm not sure what.
SQL that I ran to set up the permissions after enabling the Service Broker
EXEC sp_addrole 'sql_dependency_role'
GRANT CREATE PROCEDURE to sql_dependency_role
GRANT CREATE QUEUE to sql_dependency_role
GRANT CREATE SERVICE to sql_dependency_role
GRANT REFERENCES on
CONTRACT::[http://schemas.microsoft.com/SQL/Notifications/PostQueryNotification]
to sql_dependency_role
GRANT VIEW DEFINITION TO sql_dependency_role
GRANT SELECT to sql_dependency_role
GRANT SUBSCRIBE QUERY NOTIFICATIONS TO sql_dependency_role
GRANT RECEIVE ON QueryNotificationErrorsQueue TO sql_dependency_role
EXEC sp_addrolemember 'sql_dependency_role', 'MY_ASPNET_APP_USERNAME'
My implementation of inserting new data after fetching and thus setting up the SqlDependency (hopefully less naive!):
private void insertIntoCache(
AcademicTermLockingInfo newItem,
string itemKey,
Guid termID) {
var dbContextConnection = db.Database.Connection;
var connectionString = dbContextConnection.ConnectionString;
// important step otherwise it won't work
SqlDependency.Start(connectionString);
CacheItemPolicy policy = new CacheItemPolicy {
AbsoluteExpiration = DateTime.UtcNow.AddMonths(6)
};
CacheItem item = new CacheItem(itemKey, newItem);
using (SqlConnection connection = new SqlConnection(connectionString)) {
connection.Open();
// command which will be used to notify updates - probably want to parametrize this
using (SqlCommand command =
new SqlCommand(
String.Format("SELECT Name, LockDate FROM dbo.AcademicTerms WHERE ID = '{0}'",
termID),
connection)) {
SqlDependency dependency = new SqlDependency(command);
SqlChangeMonitor monitor = new SqlChangeMonitor(dependency);
policy.ChangeMonitors.Add(monitor);
MemoryCache.Default.Set(item, policy);
// execute once otherwise dependency not registered
command.ExecuteNonQuery();
}
}
}
Any help would be very much appreciated!
Things I've done:
Created two new users in SQL Server, net and sanba
Added every NT* login and the sa login to the net user, added net to the sql_dependency_role
Ran grant alter on schema::sql_dependency_role to net and grant alter on schema::dbo to net
Check that my local SQL Server's Broker Enabled option is True under Service Broker
Tried the web cache and the Memory Cache interchangeably (probably wouldn't change anything)
Tried making the sql command string have a fully qualified name DevUMS.dbo.AcademicTerms and dbo.AcademicTerms
I queried the sys.dm_qn_subscriptions and saw I had one subscription, good!
I queried DevUMS.sys.transmission_queue and found an excpetion!
An exception occurred while enqueueing a message in the target
queue. Error: 15517, State: 1. Cannot execute as the database
principal because the principal "dbo" does not exist, this type of
principal cannot be impersonated, or you do not have permission.
I found this SO post with the same error
The secret sauce I was missing was alter authorization on database::DevUMS to [sa]; which I found on the linked SO post's answer.
There are a number of other steps, like adding a Role to use the appropriate login, but honestly, I'm really unsure as to whether or not those are actually necessary.
I'm going to publish a little later on today, and then I'll try to do the minimal amount of steps and document that here. I found the documentation in the wild to be very scattered and poor, so I hope to have this answer be a definitive place to refer to in the future

How to get SQL Server login mappings & role membership for a user

I technically need this from a code in C#, but SQL would work as well. Say, I have a SQL Server 2008 or later login or a user account. Let's call it c_user002.
How do I get databases mapped to this user?
How do I get role membership (or permissions) for this user?
Both concepts can be best illustrated via a screenshot from the SQL Server Management Studio:
Here's a partial answer. You can find out which users have which permissions on which objects using this query:
SELECT
dp.name AS DBUser,
dp.type_desc AS UserType,
OBJECT_NAME(p.major_id) AS ObjectName,
p.permission_name AS Permission,
p.state_desc AS PermissionStatus,
dp.is_fixed_role AS BuiltInRole
FROM
sys.database_permissions AS p
LEFT OUTER JOIN
sys.database_principals AS dp
ON
dp.principal_id = p.grantee_principal_id
WHERE (p.class = 1); -- Limit to Object or Column;
Note that this only applies to the current database. You can always loop through to get them all though.

How to get option set values from sql server in an application outside crm

How to get option set value of an entity from sql server. I have developed a windows application , in which i was getting option set from crm using impersonization. But now my requirement is to get the value from sql server using sql server credentials but not with crm credentials.
select
e.Name as EntityName,
e.ObjectTypeCode,
s.AttributeName,
s.AttributeValue,
s.Value,
s.DisplayOrder
from
StringMap s
inner join EntityLogicalView e on
s.ObjectTypeCode = e.ObjectTypeCode
where
e.Name = 'new_entityname'
and s.AttributeName = 'new_optionsetname'
Direct SQL access is obviously unsupported but if you need to grab the info anyway, you need to look at the StringMap view. You can then filter by entity and attribute name as required.

Categories