Set the first Record Value of LINQ - c#

I have a DBSet which is db.Company and it contains 3 records like
id name is_active
1 company1 1
2 company2 1
3 company3 1
My Created class to transfer the records:
public class CompanyFinal
{
public int id { get; set; }
public string name { get; set; }
public string selected { get; set; }
}
My LINQ looks like this:
(from h in db.Company where h.is_active == 1 select new CompanyFinal { id = h.id, name = h.name, selected = "false" }).ToList();
No doubt this LINQ is working but i need to make the first record to be selected="true" which is the company 1 while doing it in LINQ.
How could i do that? Is it possible?
Thanks in advance

Since you're making a list, I think that computational the fasted method, which is also the best maintainable (understood by others) would be to just assign the first element:
(Using method syntax, showing an alternative select)
var resultingList = db.Company
.Where(company => company.is_active == 1)
.Select(company => new CompanyFinal()
{
id = company.id,
name = company.name,
selected = "false",
})
.ToList();
if (resultingList.Any())
resultingList[0].selected = true;
If you are not sure whether you want to convert it to a list, for instance because you want to concatenate other Linq functions after it, consider using this overload of Enumerable.Select
var result = db.Company
.Where(company => company.is_active == 1)
.Select( (company, index) => new CompanyFinal()
{
id = company.id,
name = company.name,
selected = (index == 0) ? "true" : "false",
});
By the way, consider changing your CompanyFinal class such that selected is a bool instead of a string, that would make your code less error prone. For instance, after construction Selected is neither "true" nor "false". Users are able to give it a value like "TRUE" or String.Empty
If your class has users that really need a string property selected instead of a Boolean property consider keeping a get property for it:
public class CompanyFinal
{
public int id { get; set; }
public string name { get; set; }
public bool Selected {get; set;}
// for old user compatability:
public string selected
{
get { return this.Selected ? "true" : "false"; }
}
}
The following will go wrong:
if (companyFinals[0].selected == "True") ...
versus:
if (companyFinals[0].Selected)

What if we define a local variable
var counter = 1;
(from h in db.Company where h.is_active == 1 select new CompanyFinal { id = h.id, name = h.name, selected = (counter++ == 1 ? "true" :"false") }).ToList();

From your result:
var companies = (from h in db.Company
where h.is_active == 1 select h).ToList();
var companyFinals = (from h in companies
select new CompanyFinal {
id = h.id,
name = h.name,
selected = "false"
}).ToList();
var firstCompany = companies.FirstOrDefault();
if (firstCompany != null) {
firstCompany.selected = true;
}
// save result back to database
There is no way to do it in 1 operation other than writing a stored procedure.

Related

C# Get element of List where value of List in List matches

I have a problem. In my C# code I have a List<Set> lstSets. Inside a Set I have another List<Picture> Pictures.
The picture class looks like this:
public class Set
{
public int Id { get; set; }
public List<Picture> Pictures{ get; set; }
}
And the picture class looks like this:
public class Picture
{
public int Id { get; set; }
public string Name { get; set; }
}
Now I have a random picture where I know the Id and Name, but I need to get the Index of the Picture inside the Pictures list and I need to know the Set Id.
I know the code how I can get something out of one list:
myList.FindIndex(a => a.prop == prop);
But this is a list in a list.
So I want:
int SetId = ....
int PictureIndex = ....
How can I do that?
The following Linq expression returns an Id of a Set by picture Id by using FirstOrDefault and Any methods. If there is no such item, the index is set to 0 using null coalescing operator ??
var setId = lstSets.FirstOrDefault(l => l.Pictures.Any(p => p.Id == pictureId))?.Id ?? 0;
This code can be used to get an index of image inside Pictures collection of a Set
var index = 0;
foreach (var set in lstSets.Where(set => set.Pictures.Any(p => p.Id == pictureId)))
{
index = set.Pictures.FindIndex(p => p.Id == pictureId);
}
It attempts to find an index of picture inside every Set object. There is also an option to look through all Pictures of all Set items using SelectMany method
Please try this;
int setId = -1;
var picIndex = -1;
foreach (var set in lstSets)
{
picIndex = set.Pictures.FindIndex(p => p.Id == picToFind.Id && p.Name == picToFind.Name);
if (picIndex > -1)
{
setId = set.Id;
break;
}
}

LINQ- Get the Index of an element in a collection (grouping by multiple/conditional fields)

I am trying to solve the following LINQ problem: to get the correct index of an element in a collection of objects (if element is found) or return the next index that should be assigned to it (if not found).
My scenario is a bit more complex than that one: https://coderwall.com/p/iqrkuq/get-the-index-of-an-element-in-a-collection-via-linq since the class I am dealing with is as follows:
public class PersonIdentifier
{
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime? BirthDateDate { get; set; }
public string PersonID { get; set; } //this field is a concatenation of FirstName + LastName + **the index associated to the birthdate**.
}
I can group by or split using any of the 3 first properties. Each of them depends on a boolean condition:
bool SplitByFirstName; //value can be true or false
bool SplitByLastName; //value can be true or false
bool SplitByBirthDate = true; //value is always true because the **purpose of the method is to get the correct index associated to a given birth date.**
My collection is a list as follows:
private static IList<PersonIdentifier> PersonList =
new List<PersonIdentifier>()
{
new PersonIdentifier() { FirstName = "John", LastName = "DOE", BirthDateDate = new DateTime(2001, 1, 1), PersonID = "JohnDOE1" },
};
Actually, I tried this:
private static int GenerateIndice(bool splitByFirstName, bool splitByLastName, string relatedFirstName, string relatedLastName, DateTime? birthDate)
{
if (PersonList.Any())
{
if (splitByFirstName == true && !string.IsNullOrEmpty(relatedFirstName))
{
//TODO
}
if (splitByLastName == true && !string.IsNullOrEmpty(relatedLastName))
{
//TODO
}
//remember that SplitbyBirthDate is always true.
if (birthDate != null)
{
var results = PersonList.GroupBy(p => new { p.BirthDate });
int indice = results.Where(ex => ex.Key.BirthDate.HasValue && ex.Key.BirthDate == birthDate).Count();
if (indice == 0)
{
return results.Distinct().Count() + 1;
}
else
{
return results.Select((ex, i) => new
{
Item = ex,
Position = i
}).Where(m => m.Item.Key.BirthDate == birthDate).First().Position + 1;
}
}
}
return 1;
}
This seems to always return the correct index associated to the birthdate. However, the code should work for any combination of the boolean values:
combination of the 3 boolean possible values
When adding another John DOE (with a different birth date), the index returned should be 2 in this scenario as we already have 1 John DOE in the list.
I need your help please. Thanks guys and sorry for the english as i am a french speaker.
Some scenarios to explain the usage of the bools
usage of the bools
It's not clear to me what these splitByFirst/Last/Birthdate bools are trying to achieve. I recommend looking into the Select Overload which will project an index along with your the person object in your list. Select Overload
[edit]
You're not really finding the "index" of an item in you collection, you're finding the count of a items with similar properties. At some point you need to decide which properties you'd like to be in common. you can do this with a series of lambda functions, or by crafting a concatenated (not split) string, but at some point you need to make the determination of what properties you want to be in common.
this is what i came up with.
void Main()
{
var people = new List<Person>();
var personOne = new Person{ FirstName = "jeff", LastName = "my name is", BirthDate = DateTime.Today};
people.Add(personOne);
Console.WriteLine(AddPerson(personOne, people, GroupCriteria.Birthday));
Console.WriteLine(AddPerson(personOne, people, GroupCriteria.BirthdayFirstName));
Console.WriteLine(AddPerson(personOne, people, GroupCriteria.BirthdayFirstNameLastName));
Console.WriteLine(AddPerson(personOne, people, GroupCriteria.BirthdayLastName));
var personTwo = new Person{ FirstName = "not jeff", LastName = "my name is", BirthDate = DateTime.Today};
people.Add(personTwo);
Console.WriteLine(AddPerson(personTwo, people, GroupCriteria.Birthday));
Console.WriteLine(AddPerson(personTwo, people, GroupCriteria.BirthdayFirstName));
Console.WriteLine(AddPerson(personTwo, people, GroupCriteria.BirthdayFirstNameLastName));
Console.WriteLine(AddPerson(personTwo, people, GroupCriteria.BirthdayLastName));
}
int AddPerson(Person newPerson, List<Person> people, GroupCriteria crit)
{
Func<Person, bool> countFunc = p => p.BirthDate == newPerson.BirthDate; ;
switch(crit)
{
case GroupCriteria.Birthday:
countFunc = p => p.BirthDate == newPerson.BirthDate;
break;
case GroupCriteria.BirthdayFirstName:
countFunc = p => p.BirthDate == newPerson.BirthDate && p.FirstName == newPerson.FirstName;
break;
case GroupCriteria.BirthdayLastName:
countFunc = p => p.BirthDate == newPerson.BirthDate && p.LastName == newPerson.LastName;
break;
case GroupCriteria.BirthdayFirstNameLastName:
countFunc = p => p.BirthDate == newPerson.BirthDate && p.FirstName == newPerson.FirstName && p.LastName == newPerson.LastName;
break;
}
var index = people.Count(countFunc);
if(index == 0)
return people.Count + 1;
return index;
}
public class Person
{
public string FirstName {get; set;}
public string LastName {get; set;}
public DateTime BirthDate {get;set;}
}
public enum GroupCriteria
{
Birthday,
BirthdayFirstName,
BirthdayLastName,
BirthdayFirstNameLastName
}
It seems like a silly exercise. that doesn't have a ton to do with linq. Would love to see someone smarter than me comes up with.

LINQ searching a List that contains a Class with objects

I'm new at C#, I know how to do a LINQ search to a List with one field/type, but not with many types of an object. I created a List
List<Reader> results = new List<Reader>();
That contain this class:
public class Reader
{
public int ID { get; set; }
public string Name { get; set; }
public string Course { get; set; }
public int Grade { get; set; }
public Reader(int id, string name, string course, int grade)
{
ID = id;
Name = name;
Course = course;
Grade = grade;
}
}
I want to search it with LINQ and match the ID and Name of a user that entered the site.
If this two fields are the same I want to take from the List the users Course and Grade.
Any suggestion how to do it ?
A simple Where for condition(s) and Select for representation should do:
List<Reader> results = ...
var data = results
.Where(item => item.ID == userID && item.Name == userName)
// .OrderBy(item => item.Course) // uncomment if you want to order by course
.Select(item => $"Course: {item.Course} Grade: {item.Grade}");
foreach (var record in data)
Console.WriteLine(record);
First, let's assume that you have two variables that hold the values introduced by the user. Those variables are userName of type string and id of type integer. If you just want a variable that holds the course and the Grade you could select a new anonymous type and do the query like this:
var values= results
.Where(item => item.ID == userID && item.Name == userName)
.Select(item => new { Course = item.Course, Grade = item.Grade });
then you could use the values like:
values.Grades
values.Course
var Selecteduser = results.Where(x => x.Name == selectedname && x.ID == ID).ToList();
if (Selecteduser.Count != 0)
{
//found match ..(Selecteduser[0])
string selectedcourse = Selecteduser[0].Course;
int selectedgrade = Selecteduser[0].Grade;
}
else
{
//coudlnt find match
}

How to get filtered list based on common items in two lists in c#

I am trying to get a list filtered based on the matches of one of the properties with a property of another list.
In below example, only the items which have common 'name' between both lists should be filtered in 1st list. Can some one tell me the most concise way of doing it?
class TCapability
{
public string Name { get; set; }
public int Id { get; set; }
}
class PCapability
{
public string Name { get; set; }
public int Code { get; set; }
}
Input:
var capability = new List<TCapability>()
{
new TCapability() {Name="a", Id=1},
new TCapability() {Name="b", Id=2},
new TCapability() {Name="c", Id=3}
};
var type2Capability = new List<PCapability>()
{
new PCapability() {Name="a", Code=100},
new PCapability() {Name="b", Code=200},
new PCapability() {Name="d", Code=300}
};
Expected Output:
capability =
{
{ Name="a", Id=1 },
{ Name="b", Id=2 }
}
var result = capability.Where(c => type2Capability.Any(c2 => c.Name == c2.Name));
you can try use join clause like this
capability = (from a in capability
join b in type2Capability on a.Name equals b.Name
select a).ToList();
UPDATE on comment if type2Capability can have duplicate names
capability = (from a in capability
join b in type2Capability on a.Name equals b.Name into f
where f.Any()
select a).ToList();
If the lists can get long then a HashSet can speed things up.
var set = new HashSet<string>(type2Capability.Select(t => t.Name));
var res = capability.Where(c => set.Contains(c.Name));

LINQ IQueryable

I have a Menu class that has a IQueryable property called WebPages. In the following statement I am returning Menu items based on a match but I need to include the Webpages property. Here is what I have at the moment.
var allCategories = Menu.All().Where(x => x.CategoryID == 4 && x.Visible)
I need to extend it to check a property in the WebPage class, something like this..
var allCategories = Menu.All().Where(x => x.CategoryID == 4 && x.Visible && x.WebPages.Roles.Contains(User.Identity.Name))
That won't compile but I hope you get the jist of what I am trying to do.
NOTE: The Webpage property is filled by the PageID not CategoryID but not sure if that makes a difference??
Here are a brief outline of my classes.
public partial class Menu: IActiveRecord
{
public int ID {get; set;}
public int CategoryID {get;set;}
public bool Visible {get;set;}
public int PageID {get;set;}
public IQueryable<WebPage> WebPages
{
get
{
var repo=NorthCadburyWebsite.Models.WebPage.GetRepo();
return from items in repo.GetAll()
where items.ID == _PageID
select items;
}
}
}
public partial class WebPage: IActiveRecord
{
public int ID {get;set;}
public string Roles {get;set;}
}
If I understand the problem correctly, you want something like this:
var menuItems =
from menuItem in Menu.All()
where menuItem.Visible
and (
menuItem.WebPages.Contains(
webPage => webPage.Roles.Contains(
"role"
)
)
or menuItem.PageIsNull
)
select menuItem;
This should select only menu items joined to pages with the appropriate role.
This should do it for you mate. You just need to say WebPages.Any, this will return true if any menus contain a webpage with your specified role.
var allCategories = menus.Where(menu => menu.CategoryID == 1 && menu.Visible && menu.WebPages.Any(webPage => webPage.Roles.Contains(roleToSearchFor)));
So the key bit that you need to add is this.
menu.WebPages.Any(webPage => webPage.Roles.Contains(roleToSearchFor))
Using the Any() function is very efficient as it will stop looking as soon as it finds a match.
If you used Where() and then Count() it would iterate through all the Webpages to find all matches and then iterate through the results to count them, so that would be much less efficient.
Below is a full source example for you to try.
namespace DoctaJonez.TestingBrace
{
public partial class Menu //: IActiveRecord
{
public int ID { get; set; }
public int CategoryID { get; set; }
public bool Visible { get; set; }
public int PageID { get; set; }
public IQueryable<WebPage> WebPages { get; set; }
}
public partial class WebPage //: IActiveRecord
{ public int ID { get; set; } public string Roles { get; set; } }
public static class Launcher
{
/// <summary>
/// The Main entry point of the program.
/// </summary>
static void Main(string[] args)
{
Menu myMenu1 = new Menu
{
ID = 1,
CategoryID = 1,
PageID = 1,
Visible = true,
WebPages = new List<WebPage>()
{
new WebPage { ID = 1, Roles = "Role1" },
new WebPage { ID = 1, Roles = "Role2" },
new WebPage { ID = 1, Roles = "Role3" },
}.AsQueryable()
};
Menu myMenu2 = new Menu
{
ID = 1,
CategoryID = 1,
PageID = 1,
Visible = true,
WebPages = new List<WebPage>()
{
new WebPage { ID = 1, Roles = "Role3" },
new WebPage { ID = 1, Roles = "Role4" },
new WebPage { ID = 1, Roles = "Role5" },
}.AsQueryable()
};
Menu myMenu3 = new Menu
{
ID = 1,
CategoryID = 1,
PageID = 1,
Visible = true,
WebPages = new List<WebPage>()
{
new WebPage { ID = 1, Roles = "Role5" },
new WebPage { ID = 1, Roles = "Role6" },
new WebPage { ID = 1, Roles = "Role7" },
}.AsQueryable()
};
List<Menu> menus = new List<Menu>() { myMenu1, myMenu2, myMenu3 };
string roleToSearchFor = "Role3";
var allCategories = menus.Where(menu => menu.CategoryID == 1 && menu.Visible && menu.WebPages.Any(webPage => webPage.Roles.Contains(roleToSearchFor))).ToList();
return;
}
}
Try changing the
public IQueryable<WebPage> WebPages
to
public IEnumerable<WebPage> WebPages
I think LINQ queries return IEnumerable...
DoctorJonez thanks!!!
I'm putting this here as I have more space. I have 11 records in the Menu table, only 1 with a PageID set however if I use
var test = Menu.All().Where(x => x.WebPages.Any(pages => pages.Roles.Contains(Roles.GetRolesForUser()[0])
I get 11 records as the SQL run is this
SELECT [t0].[CategoryID], [t0].[CreatedBy], [t0].[CreatedOn], [t0].[ID], [t0].[ImageID], [t0].[ImageIDHover], [t0].[Locale], [t0].[ModifiedBy], [t0].[ModifiedOn], [t0].[OrderID], [t0].[PageID], [t0].[ParentID], [t0].[Title], [t0].[URL], [t0].[Visible]
FROM [dbo].[Menu] AS t0
WHERE EXISTS(
SELECT NULL
FROM [dbo].[WebPage] AS t1
WHERE ([t1].[Roles] LIKE '%' + 'User' + '%')
)
If I run this I get the 1 record
var test = Menu.All().Where(x => x.WebPages.Any(pages => pages.Roles.Contains(Roles.GetRolesForUser()[0]) && pages.ID == x.PageID));
The SQL for this is
SELECT [t0].[CategoryID], [t0].[CreatedBy], [t0].[CreatedOn], [t0].[ID], [t0].[ImageID], [t0].[ImageIDHover], [t0].[Locale], [t0].[ModifiedBy], [t0].[ModifiedOn], [t0].[OrderID], [t0].[PageID], [t0].[ParentID], [t0].[Title], [t0].[URL], [t0].[Visible]
FROM [dbo].[Menu] AS t0
WHERE EXISTS(
SELECT NULL
FROM [dbo].[WebPage] AS t1
WHERE (([t1].[Roles] LIKE '%' + 'User' + '%') AND ([t1].[ID] = [t0].[PageID]))
)
Is this a bug in Subsonic or am I not understanding it correctly?
The problem with Any() is that in the SQL as long as one record exits, doesn't matter which record it will return data.
I think effectively I am wanting an UNION SQL like below but I don't know how I re-engineer that into C#/Subsonic
select m.* from menu m where pageid is null
union
select m.* from menu m
join webpage p
on p.id = m.pageid
where p.roles like '%User%'
I want to return all menu records and for those with a PageID set that the corresponding WebPage has the user's role in it. If the user's role is not in the WebPage then I don't want to see it in my results.

Categories

Resources