Convert LINQ with Model To Array - c#

I'm trying to create a LINQ to get the records in Personnel table that exist in Users table. Here's the tutorial I'm currently following: Convert the Results of a LINQ Query to an Array.
However, when I try to implement it in my codes I'm having an error: 'UserModel[]' does not contain a definition for 'Contains' and the best extension method overload 'Queryable.Contains<string>(IQueryable<string>, string)' requires a receiver of type 'IQueryable<string>'
var users = from u in db.USR_MSTR select new UserModel { emp_id = u.EMP_ID };
UserModel[] userList = users.ToArray();
var matches = from p in db.PERSONNEL_MSTR
where userList.Contains(p.EMP_ID) //userList is generating the error above
select p;

Contains is awaiting for UserModel instance to be passed, that's why you get error. Just use .Any() instead:
var matches = from p in db.PERSONNEL_MSTR
where userList.Any(u=> u.ID == p.EMP_ID)
select p;
What it does here is: If p.EMP_ID is found inside userList, than it is selected.

Actually you made a mistake in this
userList.Contains(p.EMP_ID)
userList is an IQueryable<UserModel> object, it not an IQueryable<string> array, on the other hand p.EMP_ID is a string, that the reason why you got that error.
You need to fix it as following
List<string> userIdList = users.Select(u => u.emp_id.ToString()).ToList();
var matches = from p in db.PERSONNEL_MSTR
where userIdList.Contains(p.EMP_ID)
select p;

Related

What is the best way to write a two column query in LINQ to Entity 6? And save the results to two different variables?

How would you write "SELECT col.a, col.b FROM TABLE WHERE ID = 1" in LINQ to Entity 6 so that you could save col.a into variable A and col.b into variable B. You can do this with SqlReader by retrieving the index or column name, but with LINQ to Entity it is returned as one object. When returning a two field LINQ query to a list, both field are saved to the first index of the list and can only be accessed as the same list element. Is it standard to create two LINQ queries, one for each variable? Or am I missing part of the process?
Current query:
var result = (from col in cxt.Table
where col.ID == "1"
select new {col.a, col.b}).ToList();
If you are expecting exactly one record to return from database then what you can do:
var result = cxt.Table.FirstOrDefault(x => x.ID == "1");
//Notice that might be null if has not result
var a = result.a;
var b = result.b;
Will look very similar in query syntax but I think this method syntax neater in this case
I am not sure what exactly you are looking for. But selecting two variable by Linq is not so hard.
var value = (from ta in db.YourTable
where ta.ID = id
select new {
A = ta.a,
B = ta.b
}).FirstOrDefault();
var a = value.A;
var b = value.B;
If you use ToList() instead of FirstOrDefault(), you will get a list contain zero or more objects. You can simply use a loop to get field from each object.
forach(var value in values)
{
var a = value.A;
var b = value.B;
}

Select list with linq

I have 2 tables in a database, and one class in C# (Letter).
Tables: tblUser(Id, Name), tblLetter(Id, UserId, Title)
Letter: (Id, Title, UserName)
I want select data with linq, and use this code:
List<Letter> lst = new List<Letter>();
lst = (from l in l.tblLetter.ToList()
select new {l.Id, l.Title, UserName = l.tblUser.Name}
).ToList();
and:
List<Letter> lst = new List<Letter>
(from l in l.tblLetter.ToList()
select new {l.Id, l.Title, UserName = l.tblUser.Name});
but get this error:
Cannot implicitly convert type...
As #SnowYetis comments, you are actually selecting an instance of a new, anonymous type in your code. That's what the syntax new { ... } does. Notice that there's no type name after the new directive.
If your Letter type has the properties Id, Title, UserName then all you need to do is change new { ... } to new Letter { ... }.
If not, then we probably need more information than you're giving us—for example, the definition of the Letter type.
There are a few issues in your code:
l.tblLetter.ToList() returns all records from your table. You typically don't call ToList() until the end of your query, to get just the data you need and no more.
You want to do a join between the two tables to get the matching user name.
If you want to return a collection of Letter, you can create instances of that in your select statement instead of creating an anonymous type.
Try this:
var lst = (from l in l.tblLetter
join u in tblUser on l.UserId equals u.Id
select new Letter
{
Id = l.Id,
Title = l.Title,
UserName = u.Name
}).ToList();

Joining two IQueryable variables of different types together using LINQ

The columns names and types are identical, however it's coming from two separate entities. Here is a simplified example:
--Query View
var v_res = from s in db.V_CMUCUSTOMER
select s;
--Values from table less values from view
var res = from s in db.CMUCUSTOMERs
where !(from v in v_res
select v.ID).Contains(s.ID)
select s;
--join table and view values into one variable
var res_v_res = (from c in res
select c).Union(from v in v_res
select v);
I get the following error however:
Instance argument: cannot convert from 'System.Linq.IQueryable' to System.Linq.ParallelQuery
If you specify a new anonymous type and use ToList() for both then you should be able to Union them as follows :
var v_res = (from s in db.V_CMUCUSTOMER
select new { custName = s.customer_name custAddress = s.address}).ToList();
--Values from table less values from view
var res = (from s in db.CMUCUSTOMERs
where !(from v in v_res
select v.ID).Contains(s.ID)
select new { custName = s.customer_name custAddress = s.address }).ToList();
--join table and view values into one variable
var res_v_res = v_res.Union(res);
This may be onerous if there are dozens of columns but should still work.
When I run a similar query in LINQPad, I get an error message claiming that s in Contains(s.ID) is not defined in this context.
If I replace && with where all queries are successfully executed.

problem using foreach in linq query result

I have linq query as follows:
var result = (from Customer cust in db select new { userNameList = cust.UserName }).ToList();
i want to loop through each value in the list<>
I tried to use the foreach to accomplish this. It is stupid i could not figure it out
I'm using something like this
foreach (List<string> item in result)
{
if (item.ToString() == userName)
{
userExistsFlag = 1;
}
}
But the .net compiler is just freaking out:
and giving me these errors
Cannot implicitly convert type 'System.Collections.Generic.List' to 'System.Collections.Generic.List'
Cannot convert type 'AnonymousType#1' to 'System.Collections.Generic.List'
Thanks in anticipation
OF ALL THESE IMPLEMENTATIONS WHICH ONE IS MOST EFFICIENT AND CONSUMES LESS RESOURCES.
IT WOULD BE KIND ENOUGH IF SOME ONE CAN CLARIFY THIS FOR ME.
Shorter using Linq:
bool userExistsFlag = result.Any( x=> x.userNameList == userName);
As suggested in the other answers you do not need to project to an anonymous type:
var userNames = (from Customer cust in db select cust.UserName).ToList();
bool userExists = userNames.Contains(userName);
Edit:
The most efficient - if you do not need the set of user names otherwise - is to query the DB directly to check whether the user name exists, so
bool userExists = db.Any( x => x.UserName == userName);
Credit goes to #Chris Shaffer in the comments and #Cybernatet's answer - he was almost there. I would suggest you accept his answer but use Any() ;-)
Try:
var result = (from Customer cust in db select new { userNameList = cust.UserName }).ToList();
userExistsFlag = result.Where(a=> a.userNameList == userName).Count() > 0;
or
userExistsFlag = (
from Customer cust in db
where cust.UserName = userName
select cust
).Count() > 0;
If your query returns a list of names, your FOREACH loop should look like this
foreach( String name in results ){
...
}
Skip using new { userNameList = cust.UserName } which is making it an anonymous instance. You can try
var result = (from Customer cust in db select cust.UserName ).ToList();
if you're just getting the one property and want a list of strings there is no reason to use an anonymous type. code should work like this:
var result = (from Customer cust in db select cust.UserName).ToList();

Question About Querying Linq Results

When you query existing linq results, it's like they're stuck a layer deeper than the original result. Let me explain what I mean by this.
In the example below, after getting ResultSorted, to get to the data therein, you have to use RowSorted.All.TableData.Field, but in the unsorted Result, you could just do Row.TableData.Field. In the sorted data, you have to use .All to get to the rest of the data, which is like an extra layer to get to the data you're looking for.
How can I get it so I can query Result without getting this extra layer? Thanks Stack-O!
var Result =
from a in Db.Table
select new {TableData = a};
var ResultSorted =
from a in Result
orderby a.TableData.Field
select new {All = a};
foreach(var RowSorted in ResultSorted)
{
MessageBox.Show(RowSorted.All.TableData.ToString());
}
You can use
var Result =
from a in Db.Table
select a;
var ResultSorted =
from a in Result
orderby a.Field
select a;
foreach(var RowSorted in ResultSorted)
{
MessageBox.Show(RowSorted.ToString());
}
Edit:
The thing is that
select new {TableData = a};
creates a new anonymous type with a field called TableData, like this
class Tmp1
{
TableType TableData {get; set;}
}
and
select new {All = a};
creates a new anonymous type with a field called TableData, like this
class Tmp2
{
Tmp1 All {get; set;}
}
Edit 2:
If you select a directly you don't create the extra anonymous type, instead you return the TableType.
You are returning a new instance of an anonymous type in each of your LINQ queries:
select new {TableData = a};
select new {All = a};
What you are saying to the compiler is (in the first LINQ query), "Give me a new instance of an anoymous type. I want this anonymous type to have one property named TableData and I want the value for that property to be a."
If you simply return a instead of an anoymous type, you shouldn't need to go through the properties of the nested types to get the data. Try this:
var Result =
from a in Db.Table
select a;
var ResultSorted =
from a in Result
orderby a.TableData.Field
select a;
foreach(var RowSorted in ResultSorted)
{
MessageBox.Show(RowSorted.ToString());
}
var ResultSorted =
from a in Db.Table
orderby a.Field
select a.ToString();
Edit: Fixed, didn't see the first query. This should be identical now. There is no need to create anonymous objects all the time.

Categories

Resources