I'm developing a WCF RESTful web service with Entity Framework Code First.
I have a table Users with a lot of columns. I do this to get an specific user:
context.Configuration.ProxyCreationEnabled = false;
var users = from u in context.Users
where u.UserId == userId
select u;
On this table, there is a password column, and I don't want return this column.
How can I exclude password column from that select?
Its sad to say but NO
You do not have option to directly exclude any particular column. You may go with lazy loading of columns.
The easiest and non-liking method would be to include columns which you want.
Specify each column that you do want in your select statement:
var users = from u in context.Users
where u.UserId == userId
select u.UserId, u.Watever, etc... ;
another way like this,
var users = from u in context.Users
where u.UserId == userId
select new
{
col1 = u.UserId,
col2 = u.Watever
}.ToList();
You can create more than one LINQ object per table. I'd create one with the field you need and one without. It makes CRUD operations more difficult though.
Yes, you can run LINQ with certain columns excluded:
Store list of all columns in an array of string. E.g.
var arrayOfColNames = dbContext.Model.FindEntityType(typeof(TableName))
.GetProperties().Select(x => x.Relational().ColumnName).ToArray() )
Remove the unwanted columns from the above array of string. E.g.
arrayOfColNames = arrayOfColNames .Where(w => !w.Equals("password")).ToArray();
Run your LINQ select using the above filtered array of strings : https://stackoverflow.com/a/45205267/19386398
Related
I'm a junior developer and trying to convert the following linq statement to T-SQL:
var items = from u in DataContext.Users_SearchUsers(searchPara.UserFirstName,
searchPara.UserLastName,
searchPara.UserEmailAddress,
fetchOptions.page,
fetchOptions.rp,
fetchOptions.sortname,
fetchOptions.sortorder)
.ToList()
join a in DataContext.UserAccesses
.Where(x => x.Access.AccessTypeId == 4).ToList() on u.UserID equals a.UserId into accessGroup
select new {};
Can one please help me ? into accessGroup ---> (very important)
First of all you need to understand where your data is coming from. You are loading information from Users_SearchUsers on the one hand and UserAccesses on the other hand. The first query looks like
select <somecolumns>
from users
where <somefilters>;
(you need to use your actual columns and criteria, but Users_SearchUsers is not specified in the question at all). I have ignored paging here for the sake of simplicity
The second query looks like this:
select *
from user_accesses
where access_type_id = 4;
Let's join the two:
select <someoutercolumns>
from
(
select <someinnercolumns>
from users
where <somefilters>
) t1
join
(
select <someotherinnercolumns>
from user_accesses
where access_type_id = 4
) t2
on t1.user_id = t2.user_id;
These queries are probably not the exact solutions you need, but you want the answers to improve, then improve your question.
The requirement makes sense if the LINQ query is very slow. In that case you will need to refactor it in the following manner:
select <somecolumns>
from users
join user_accesses
on users.user_id = user_accesses.user_id and user_accesses.access_type_id = 4
where <somefilters>;
you can use this code
select *(you can put your columns instead *)
from Users
join UserAccesses
on Users.userid = UserAccesses.userid
where UserAccesses.typeid = 4;
I have a situation where I need data from multiple database tables.
Table 1 - has list of columns which needs to be displayed on front end html, angular kendo grid - which is configurable from separate Admin configuration.
Table 2 (joining of some other tables)- has the data which needs to be displayed on the angular front end.
My linq here which I am using currently is as below.
Query 1: to get list of columns to be displayed on Grid
var columns = from cols in _context.columns
select cols.colNames;
Query 2: Get the actual data for list
var data = from cust in _context.customer
join details in _context.custDetails on cust.id equals details.custid
join o in _context.orders on cust.id equals o.custid
where cust.id == XXXX
select new Customer
{
Id = cust.Id,
Name = cust.Name,
Address = details.Address,
City = details.City,
State = details.State,
OrderDate = o.OrderDate,
Amount = o.Amount
//15 other properties similarly
};
returns IQueryable type to Kendo DataSourceRequest
Currently, From my ui I have been make two api calls one for columns and one for getting the actual data, and show/hide the columns which are configured in the columns table.
But the problem is if anyone looks at the api calls on the network or on browser tools they could see the data being returned for the columns that are to be hidden which is a security problem.
I am looking for a single query for my api which returns the data using second query which should be smart enough to send the data only for configured columns (there could be 30 different columns) and set the other properties to null or doesn't select them at all. there are some properties which needs to be returned always as they are being used for some other purpose.
I searched many resources on how could I generate dynamic linq select using the configured columns.
Please some one help me in resolving this problem
you can do something like this. Assuming you columns tables a Boolean column Display and when it is true Column will be displayed and when it is false it wont be displayed.
var columns = (from cols in _context.columns
select cols).ToList(); // note I am getting everything not just column names here...
var data = from cust in _context.customer
join details in _context.custDetails on cust.id equals details.custid
join o in _context.orders on cust.id equals o.custid
where cust.id == XXXX
select new Customer
{
Id = cust.Id,
Name = cust.Name,
Address = details.Address,
City = details.City,
State = details.State,
OrderDate = o.OrderDate,
Amount = o.Amount
//15 other properties similarly
}.ToList();
var fileterdData = from d in data
select new Customer
{
Id = DisplayColumn("ID",columns)? cust.Id:null,
Name = DisplayColumn("Name",columns)? cust.Name:null,
Address = DisplayColumn("Address",columns)? details.Address:null,
// do similarly for all other columns
}.AsQueryable(); // returns IQueryable<Customer>
private bool DisplayColumnn(string columnName,List<Columns> cols)
{
return cols.Where(x=>x.ColumnName==columnName).First().Display();
}
So now you will have this code as part of one web API call which is going to do two SQL calls one to get columns and other to get data then you will use Linq To Entity filter columns which you dont want ( or want them to null). return this filtered data back to UI.
I have 3 tables: the User table, the Records table and the UserRecords table.
The columns are so:
UserTable
UserID | OtherUserDataFields
RecordsTable
RecordID | OtherRecordDataFields
UserRecords
UserID | RecordID
The UserRecords table tells me which users have authorization on which record. I have a function that updates the RecordsTable by receiving 2 paramaters: a record TheRecord (which contains a RecordID field) and a UserID.
I'm writing a query in the data context MyDC to fetch the record with the RecordID supplied in the parameter and test if the user is authorized on that record like this:
var RecordToUpdate = (
from r in MyDC.RecordsTable
from u in MyDC.UserRecords
where r.RecordID == TheRecord.RecordID && TheRecord.RecordID == u.RecordID
where u.UserID == TheUserID
select r).SingleOrDefault();
Will this ensure me that only records the user is authorized will be fetched? I want to avoid cases where users maliciously send a record they're not authorized on and make changes to these unauthorized records.
Thanks for your advice.
I agree with Anand, you will need a linq query:
var filterUserRecord = from u in MyDC.UserRecords
where u.UserID == TheUserID
select u;
var q1 = from r in MyDC.RecordsTable
where r.RecordID = TheRecordID
where filterUserRecord.Any(f => f.RecordID == r.RecordID)
select r;
This will be converted to the SQL query like the following:
SELECT * FROM RecordsTable rt WHERE rt.RecordID = TheRecordID AND EXISTS
(SELECT recordId FROM UserRecords ur WHERE ur.userId = TheUserID AND ur.recordID = rt.recordID)
Note that those are IQueryable<T>s and linq queries on it will produce another IQueryable<T> which will contain expressions to be wholly translated to SQL (or whatever the backend is) instead of naively evaluating it at client side.
Well I think your problem could be solved by subquery
sql:
select * from RecordsTable where recordId in
(select recordId from UserRecords where userId = #someUserId)
It could be represented in Linq as following
var filterUserRecord = from u in MyDC.UserRecords
where u.UserID == TheUserID
select u
var q1 = from r in MyDC.RecordsTable
where filterUserRecord.Any(f => f.RecordID == r.RecordID)
Details for subquery in Linq - Read from here
Perhaps read the article here which discusses how SQL Injection (which I assume should be the main security concern here) is handled in LINQ scenarios.
There is also a nice article here regarding Microsoft's security considerations for EF. It's worth a read for anyone developing with these tools!
[Edit] With regards to your last comment, you can use queries similar to those already on this page. To condense a little: If your database is normalised, to the extent that the RecordId is a unique primary key, you can bypass joins to make a query which reads a little better:
var targetRecords =
from userRecords in MyDC.UserRecords
where userRecords.UserTable.UserID == TheUserID
&& userRecords.RecordsTable.RecordID == TheRecord.RecordID
select userRecords;
var targetRecordsResult = targetRecords.SingleOrDefault();
I have separated the query from it's result 'var' here to point out that 'targetRecords' does NOT get evaluated until you call SingleOrDefault on it in order to assign to targetRecordsResult. You can of course wrap this into one statement if you wish.
If, as mentioned, your RecordID is a Unique Primary Key, you will either get the matching Record back, or null. Note that if this isn't the case, i.e. more than on Record could have the same ID, then the SingleOrDefault call can fail. If your database is designed like that, you would have to use a query more like the one which Anand has specified. That is slightly more verbose, but will return you ANY Record with a matching id for that specific user.
In terms of security, note that your SQL statement will get compiled containing the UserID, making it very difficult to tamper with. Hence my point that in this case, the scope and exposure of UserID is your main concern. If, like you have stated, the user (and any potential malitious user) has no access to the variable (via property exposure etc) then this should be more than suitable for your needs.
Try this:
var RecordToUpdate = (from u in MyDC.UserRecords
where u.UserTable.UserID == TheUserID
and u.RecordsTable.RecordID == TheRecord.RecordID).SingleOrDefault();
This will return the result for query which has specified UserID and RecordID.
how would I write linq query that would display user name instead of userID in a gridview.
var q = from u in entities.problems
join a in entities.my_aspnet_membership on u.user_id equals a.userId
join c in entities.my_aspnet_users on a.userId equals c.id
where c.id == a.userId
select new { u.problem_id, c.name, u.problem_description, u.problem_reported_datetime, u.problem_history};
What I am looking is when uasing login in the webiste only to see problems they submitted.
Bind only those columns needed to display the result. Turn off the AutoGeneratedColumns and add BoundField columns.
There are couple of issues with your query:
Where part (where c.id == a.userId) does not make sense.
Join with membership table - why is this needed? This join could potential give you multiple rows for one problem (if user has multiple roles) - eliminate if it's not needed.
For example,
var q = from u in entities.problems
join c in entities.my_aspnet_users on u.user_id equals c.id
select new {
u.problem_id, c.name, u.problem_description,
u.problem_reported_datetime, u.problem_history
};
This will give you all problems along with user name - bind the grid column with "name" column.
If you want to list the problems for only logged in user then you have to add where part such as where u.user_id = currentUserId where currentUserId variable will hold the value of logged in user.
I have five tables all with a primary key of ID
User
User_Role_Relation with Foreign Keys User_ID and Role_ID
Role
Role_Right_Relation with Foreign Keys Role_ID and Right_ID
Right
I am currently getting the Rights for the selected User with the following query in a stored procedure
SELECT DISTINCT
tbl_Right.ID, tbl_Right.Name
FROM
tbl_User_Role_Relation
INNER JOIN
tbl_Role_Right_Relation ON tbl_User_Role_Relation.Role_ID = tbl_Role_Right_Relation.Role_ID
INNER JOIN
tbl_Right ON tbl_Role_Right_Relation.Right_ID = tbl_Right.ID
WHERE
tbl_User_Role_Relation.User_ID = #User_ID
I am trying to covert this to LINQ to Entity with this code
var query = from r in context.Rights
from rrr in r.Role_Right_Relation
from rl in rrr.Role
from urr in rl.User_Role_Relation
where urr.User_ID == userid
select r;
but I get the following error
An expression of type 'Models.Role' is not allowed in a subsequent from clause in a query expression with source type 'System.Linq.IQueryable' Type inference failed in the call to 'SelectMany'
Any advise would be helpful.
Thanks.
First of all that linq query is doing a cross join, not inner join like your sql. You should check out this
Second of all, you would probably be best correctly defining the relationships between entities in the edmx and you probably won't have to join at all, instead you can use navigation properites to access parent/children and filter on those properties directly
The idea of the entity framework is you don't have to flatten the hierarchy
Edit 3
If you posted your code verbatim, then you are missing a line
from u in urr.Users
So:
var query = from r in context.Rights
from rrr in r.Role_Right_Relation
from rl in rrr.Role
from urr in rl.User_Role_Relation
from u in urr.Users
where u.User_ID == userid
select r;
Or at least there's a typo and the where should read:
where urr.User_ID == userid
resulting in:
var query = from r in context.Rights
from rrr in r.Role_Right_Relation
from rl in rrr.Role
from urr in rl.User_Role_Relation
where urr.User_ID == userid
select r;
If you use method syntax you should be able to do something like:
var user = context.Users.FirstOrDefault(u => u.Id == userId);
var rights =user.Roles.SelectMany(role => role.Rights).Distinct();
Be sure to check user is not null before getting rights