This question already has answers here:
Linq Syntax - Selecting multiple columns
(3 answers)
Closed 5 years ago.
I am trying to select multiple columns by using LinqToSql, but I am having a hard time with it. I am quite new in LinqToSql.
When I am selecting 1 column I do it like this:
string[] name = mycontext.Users.SingleorDefault(p => p.UserId == 1).UserName;
Is there anything similar for multiple columns?
I actually want to assign Name and Surname in a ListBox control
Use Anonymous Types:
var result = mycontext.Users.Where(p => p.UserId == 1)
.Select(c => new {c.UserName , c.Family ,...})
.SingleOrDefault();
You current request will query the whole user (select *).
In most cases, it is enough and you can access to each column separately :
var user = mycontext.Users.SingleorDefault(p => p.UserId == 1);
var userName = user.Username;
var password = user.Password;
// etc...
If you only need one (or several columns) but not the whole user, you can do it like this:
var userInfo = mycontext.Users.Where(p => p.UserId == 1).Select(p => new {p.UserName, p.Password}).SingleOrDefault();
var userName = userInfo.UserName;
var password = userInfo.Password;
If you prefer a collection of string in result, you can do it this way:
List<string> userInfo = mycontext.Users.Where(p => p.UserId == 1).Select(p => new List<string> { p.UserName, p.Password }).SingleOrDefault();
var username = userInfo[0];
var password = userInfo[1];
This way, the generated query will looks like Select UserName, Password From UserTable. Its usefull only if your table has a lots of columns or a heavy one (blob for example).
How it works: by calling the Where extension methods firstly, you tell .NET to not run the query immediately. It will be executed on the SingleOrDefault call. But at this moment, the query has been completed and the whole part is done in SQL.
Can't you return User object?
var user = mycontext.Users.SingleorDefault(p => p.UserId == 1)
After that you can get all properties of User without creating dynamic types
Related
This question already has answers here:
C# Linq where clause as a variable
(5 answers)
Closed 4 years ago.
Im new in LINQ,i need to pass different conditions on the same LINQ query like:
var rslt = (from t in cr.faultStat
where(parameter)
select new{
name=t.Name,
Fname=t.fname
});
the parameter seen in the where ,is the part i want to send conditions dynamicaly but i dont know how,because where accepts boolean,but i want to send something like:
string parameter="date>"2018-10-10" && id="123"
generally how should i send parameter to linq dynamically
I guess (according to your comment) actually you don't have a string but you have multiple conditions. Then i'd suggest to write your query like this:
var query = cr.faultStat;
// the user selected a min-date-filter?
if(minDate.HasValue)
{
query = query.Where(x => x.Date > minDate.Value);
}
// the user selected a max-date-filter?
if(maxInclusiveDate.HasValue)
{
query = query.Where(x => x.Date <= maxInclusiveDate.Value);
}
// the user selected an id-filter?
if(id.HasValue)
{
query = query.Where(x => x.Id == id.Value);
}
var rslt = query
.Select(x => select new
{
t.name,
t.fname, ...
});
Actually after this the database (or whatever the source is) was not even queried once due to deferred execution of above methods. You have to use a foreach or a method that does it:
int resultCount = rslt.Count(); // like this
I'm curious as to why my linq group by query returns 417 results whereas my SQL interpretation returns 419? I'm looking for duplicated emails from my list. I've checked out the result set and the two email addresses that are missing from the linq set both have accents. Does linq not recognize accents? Is there a workaround? The email field type is a nvarchar(100).
Let me know if you have any questions,
Thanks in advance!
var listOfContacts = (from contacts in something
where contacts.Team.Id.Equals(TeamGuid) && !contacts.Email.Equals(null)
select new {contacts.Id, EmailAddress = contacts.Email.ToLower()}).ToList();
//Full Contact List; exact amount matches
var dupeEmailsList = listOfContacts
.GroupBy(x => x.EmailAddress)
.Where(g => g.Count() > 1)
.Select(y => y.Key)
.ToList();
//Returns 417
SELECT Email, COUNT(*)
FROM something
WHERE Team = 'Actual Team Guid Inserted Here'
GROUP BY Email
HAVING (COUNT(LOWER(Email)) > 1 AND Email IS NOT NULL)
ORDER BY Email
//Returns 419
This is a known issue and the workaround has already been answered -> here and here
You have to explicitly tell it to ignore them.
This is from the links provided by #Bactos.
You just need to strip out what's called Diacritics, using built in C# normalization and CharUnicodeInfo.
You'll just have to make the call for each email address like so:
var listOfContacts = (from contacts in something
where contacts.Team.Id.Equals(TeamGuid) && !contacts.Email.Equals(null)
select new { contacts.Id, EmailAddress = CleanUpText(contacts.Email) }).ToList();
and the method you would need would be as follows:
private static string CleanUpText(string text)
{
var formD = text.Normalize(NormalizationForm.FormD);
var sb = new StringBuilder();
foreach (var ch in formD)
{
var uc = CharUnicodeInfo.GetUnicodeCategory(ch);
if (uc != UnicodeCategory.NonSpacingMark)
{
sb.Append(ch);
}
}
return sb.ToString().Normalize(NormalizationForm.FormC).ToLower();
}
Hope that helps!
Because of the .ToList() in your first LINQ expression, the GROUP BY is being performed within C# on the result of Email.ToLower()
This is not at all the same as the SQL query you give, where the GROUP BY is performed on the original EMAIL column, without the ToLower(). It is not surprising that the queries return different results.
I think you can try to ignore NULL values in the SELECT clause.In your LINQ query you are ingnoring NULLs.
I have 2 classes user(count-10k),address(count-1million). these are like one to many.
i am trying to map the address for users.
Using List(takes few minutes):
List<User> us = usrs.Select(u => new User { id = u.id ,email=u.email,name=u.name,addresses=adrs.Where(a=>a.userid==u.id).ToList()}).ToList();
the above works but its very slow
i changed it to use dictionary and its fast.
Using Dictionary(takes few seconds):
var dusrs = usrs.ToDictionary(usr => usr.id);
var daddrs = adrs.ToDictionary(adr => Tuple.Create(adr.id,adr.userid));
foreach (var addr in daddrs)
{
var usr = dusrs[addr.Value.userid];
if (usr.addresses == null)
{
usr.addresses = new List<Address>();
}
usr.addresses.Add(addr.Value);
}
is there any way i can write better query using list rather than dictionary?
I am just trying to see if i can write better linq using lists
thanks...
vamsee
Assuming you are keeping users and addresses in Lists for some reason, you can use a join in LINQ which will combine the two lists and use a hashed data structure internally to put them together:
var us2 = (from u in usrs
join a in adrs on u.id equals a.userid into aj
select new User { id = u.id, email = u.email, name = u.name, addresses = aj.Select(a => a).ToList() }).ToList();
Alternatively, you can convert the addresses into a Lookup and use that, but it would probably be best to just keep the addresses in a Lookup or create them in a Lookup initially if possible:
var addressLookup = adrs.ToLookup(a => a.userid);
List<User> us = usrs.Select(u => new User { id = u.id, email=u.email, name=u.name, addresses=addressLookup[u.id].ToList() }).ToList();
In my test cases which is faster seems to depend on how many users versus addresses match.
I am trying to link up the RestaurantId in the RestaurantReservationEventsTbl with the RestaurantID in the RestaurantTbl to display reservations that are only made for the currently logged in restaurant.
I am receiving the following error in my code operator == cannot be applied to operands of type int and iqueryable int
Here is what I am doing in my home controller
var RestaurantIDRestaurantTbl = from r in db.Restaurants select r.RestaurantID;
//var listOfRestaurantsReservations = db.RestaurantReservationEvents.ToList();
var listOfRestaurantsReservations = db.RestaurantReservationEvents.Where(x => x.RestaurantID == RestaurantIDRestaurantTbl).ToList();
//return View(restaurants.Where(x => x.RestaurantEmailAddress == UserEmail).ToList());
//create partial view called _RestaurantReservation
return PartialView("_RestaurantReservations", listOfRestaurantsReservations);
You have to change your code to materialize the restaurantIds like this:
var RestaurantIDRestaurantTbl = (from r in db.Restaurants
select r.RestaurantID).ToList();
Then you may change the code as below for the comparison to work:
var listOfRestaurantsReservations = db.RestaurantReservationEvents.Where(x => RestaurantIDRestaurantTbl.Contains(x.RestaurantID)).ToList();
Anyway this is not the best solution. I will write another example for you, just try this example if it is working or not and let me know for the result.
I would considering changing the code as below to be much more efficient:
var listOfRestaurantsReservations = (from r in db.Restaurants
join e in db.RestaurantReservationEvents
on r.RestaurantID equals e.RestaurantID
//where r.RestaurantID == something //if where condition needed
select e).ToList();
If your tables are not connected with foreignkeys please consider to read this documentation here to make a better structure of the tables since they are related to each-other.
If your tables are related as in documentation article you might have something like that:
var RestaurantIDRestaurantTbl = db.Restaurants.SingleOrDefault(x => x.RestaurantID == something);
if(RestaurantIDRestaurantTbl != null)
{
var listOfRestaurantsReservations = RestaurantIDRestaurantTbl.RestaurantReservationEvents.ToList();
}
{
// This will give you a list of IDs
var RestaurantIDRestaurantTbl = db.Restaurants
.Select(p => p.RestaurantID)
.ToList();
// Using .Any() is a better choice instead of .Contains()
// .Contains is used to check if a list contains an item while .Any will look for an item in a list with a specific ID
var listOfRestaurantsReservations = db.RestaurantReservationEvents
.Where(p => RestaurantIDRestaurantTbl.Any(r => r.pRestaurantID == p))
.ToList();
}
I have the following two objects:
User
class User {
public int role;
}
Role
class Role {
public int id;
public string name;
}
be note that role property inside User is int and not Role, that's our limitations.
I want to join between all the users and each of his role. In the mapping objects there is no reference as you can understand, just a simple type (int).
How do I do that join statement?
It's called a theta join:
var a = (from u in session.Query<User>()
from r in session.Query<Role>()
where u.role == r.id
select new { u.Username, Role = r.name }).ToList();
Assuming you have a Username property on the User class.
Yes, this "theta join" (as I just learned this term) is very handy and let's us not worry about putting in pointless mapping relationships.
WARNING HOWEVER IN USING THIS!!! This tripped me up a lot.
Adding to the above example...
var list = new List<int>( { 2, 3 } ); // pretend in-memory data from something.
var a =
(from u in session.Query<User>()
from x in list
from r in session.Query<Role>()
where u.role == r.id
where r.id == x.id // pretend list wants to limit to only certain roles.
select new { u.Username, Role = r.name }).ToList();
THIS WILL BOMB with some NotSupported exception.
The trick is that anything coming from NHibernate Session must come LAST. So this alteration WILL work:
var a =
(from x in list
from u in session.Query<User>()
from r in session.Query<Role>()
where u.role == r.id
where r.id == x.id // pretend list wants to limit to only certain roles.
select new { u.Username, Role = r.name }).ToList();
And and BTW, you can use join as well, however you have to make sure if you have any nullable data types, that you use the .Value if you are joining to something not-nullable.
var a =
(from x in list
from u in session.Query<User>()
join r in session.Query<Role>() on u.role equals r.id
where r.id == x.id // pretend list wants to limit to only certain roles.
select new { u.Username, Role = r.name }).ToList();
And while we're at it, let's say you have a method that has some dynamic condition. In this example the 'list' which could be a list of roles to filter by, but don't filter at all if the list is not there. Well, if you do the .ToList() then you are causing this query to execute immediately. But instead you can add a condition and then execute it later:
var a =
from u in session.Query<User>()
join r in session.Query<Role>() on u.role equals r.id
where r.id == x.id // pretend list wants to limit to only certain roles.
select new { u.Username, Role = r.name, RoleID = r.id }; // Adding the Role ID into this output.
if (list != null) // assume if the list given is null, that means no filter.
{
a = a.Where(x => list.Contains(x.RoleID));
// WARNING. Unfortunately using the "theta" format here will not work. Not sure why.
}
var b = a.ToList(); // actually execute it.
var c = a.Select(x => new { x.Username, x.Role }).ToList() // if you insist on removing that extra RoleID in the output.
One last thing.. Sometimes some simple logic will fail when executed in the select new { .. } part. I don't have an explanation. In our case the logic was just converting a DB value of a uint to an Enumerator of a model. But to get around that, I just avoided doing that conversion while reading the data but saved the value. Then in a later step, after the data was loaded, I just did the conversion in another LINQ statement.
DISCLAIMER: While I wrote many of these things all the past several weeks, I did not put this code into my compiler to verify 100%.