Select multiple columns for AutoComplete result using LinQ - linq

I'm setting up an AutoComplete function that will return a list of Holdings with associated Codes. (e.g. Google GOOGL, Amazon AMZ, etc)
I am able to get the results using the following code:
var names = _context.UMA
.Where(p => p.Name.Contains(term) || p.Code.Contains(term))
.Select(p => p.Name );
This code works and returns a list of Holding Names.
I now want to add the Holding Codes in the result.
I changed the last line of Code to this:
.Select(p => new {p.Code, p.Name})
But the result only shows blank lines (but the correct number of blank lines.)
If I change the last line to just this:
.Select(p => new { p.Name})
I still get blank lines (and, yes, correct number of blank lines.)
Any help always appreciated!

Related

How to search for substring in a list of strings in episerver find

I have a list of strings like this
"Users": [
"usrName|Fullname|False|0|False|False",
"usrName|Fullname|False|0|False|False",
"usrName|Fullname|False|0|False|False",
"usrName|Fullname|False|0|False|False",
"usrName|Fullname|False|0|False|False",
]
In my episerver/optimizely code I want to match items. I have written this line of code
searchResult.Filter(x => x.Users.MatchContained(k=> k.Split('|')[3], "0"));
I am trying to get all Users where after splitiing on 'pipe' I get 0 at index 3. I am not getting the result, infact I get an exception.
What am I doing wrong here?
Since you left out A LOT of details these are my assumptions
Users is an IList<string> Users
You are trying to get all Users within that list/array where index 3 equals 0
What we don't know is, among others
Is there more than one page instance that have the Users instance filled?
Anyway, this cannot be solved using any Find API with the current system design. Instead you need to rely on linq to parse the result, but then the Find implementation may not be necessary.
var searchClient = SearchClient.Instance;
var search = searchClient.Search<BlogPage>();
var result = search.GetContentResult();
var usersResult = result
.SelectMany(x => x.Users)
.Where(x => x.Split('|')[3].Equals("0"));
This would create and return an object similar to this, since I'm using SelectMany the array would contain all users throughout the systems where there are matched pages from the search result.
If you for whatever reason would like to keep or see some page properties there are alternative approaches where you construct a new object within a select and remove any object where there where not matched users
var searchClient = SearchClient.Instance;
var search = searchClient.Search<BlogPage>();
var result = search.GetContentResult();
var usersResult = result
.Select(p => new
{
PageName = p.Name,
ContentLink = p.ContentLink.ToString(),
Users = p.Users.Where(x => x.Split('|')[3].Equals("0"))
})
.Where(x => x.Users.Any());
If you like to keep using Find for this kind of implementations you must store the data in a better way than strings with delimiters.

LINQ select column(s) of table before doing multiple joins

After running the query below and hovering over "usersToWork" when debugging, I can view all of the properties of the single entry that I get returned to me in addition to the other tables that have relations to this value. What I need to display to the user is the "Lines.Id" (Lines being the table and Id being the column in the Lines table) value, however that value gets lost from the SelectMany() statements. Is there anyway to select that "Lines.Id" value to include in the final value that I get from all of my joins? In the code below, I commented out what I want but I can't place that there otherwise I get error on the first SelectMany statement saying 'int' does not contain a definition for 'Shifts' and no extension method 'Shifts' accepting a first argument of type 'int' could be found.'
Correct me if I'm wrong but SelectMany() selects all of the columns from what you want to join on. In this case, in the first SelectMany() I get only values from the "Shifts" table and in the second SelectMany() I get only values from the "Users" table. Why is this different from the SQL join? When joining in SQL you can get every column as you join them together, SelectMany() yields only the values of the second table that you are joining on. Is it even possible to get that value in the "Lines" table or will I have to do another query? Any help would be great.
int idEnteredByUser = 123;
var usersToWork = entityDataModel.Lines
//....NOT IN MY CODE NOW....
// .Select(line => line.Id)//THIS IS WHAT I NEED.
// .Select(line => line.Description, line.Id//OR THIS TO RETURN TWO VALUES IF POSSIBLE
//This is my current code, I need to include on of the select lines above.
.SelectMany(line => line.Shifts) //Join lines on shifts.
.Where(shift => shift.EndTime >= DateTime.Now) //Join restricted times.
.SelectMany(user => user.Users) //Join the restricted shift times on users.
.Where(user => user.UserId == idEnteredByUser ); //Only look for the specific user
This works much easier using LINQ query syntax.
I'm assuming that you made a typo in your posted code and that user is a property of shift.
var idEnteredByUser = 123;
var usersToWork =
from line in entityDataModel.Lines
from shift in line.Shifts
where shift.EndTime >= DateTime.Now
from user in shift.Users
where user.UserId == idEnteredByUser
select new
{
Description = line.Description,
Id = line.Id
};

LINQPAD - Read in a csv and store columns into lists

Basically I have a csv of the format of shown below:
The csv has 11 columns with the first five and last five being the exact same.
I want to be able to read in the csv and store all instances of the first and fifth column (Period and Payout) in a list where they have values and do the same with the sixth and eleventh column in another list.
The purpose of this is to compare payouts that match on period between different lists.
Any help whatsoever is appreciated.
Period,IndexId,Id,Date,Payout,,Period,IndexId,Id,Date,Payout
,,,,,,109,75,80010081,03-Sep-2016 05.28.37,239073.74999996735
,,,,,,202,75,80044661,21-May-2013 06.49.16,3.0170290500000052E7
,,,,,,8505,75,80035051,28-May-2013 03.32.41,8835437.250000026
109,128,80010081,03-Sep-2016 05.28.37,239073.749999967,,,,,,
202,128,80044661,21-May-2013 06.49.16,3.01702905000001E7,,,,,,
934,128,80041031,13-Oct-2015 20.22.03,1.55494005E7,,,,,,
Try this one:
var values = File.ReadLines(path).Skip(1)
.Select(x => x.Split(','))
.Where(x => x[0] != string.Empty)
.Select(x => new { Period = x[0], Payout = x[4] })
.ToList();

Any way to add a property using linq?

So I have this list, it returns an ID and a thumbnail. ex. List<PersonPicture>
and I have this list, List<Person> which has a property named "picture" in it.
Is there anyway that I can merge this two properties and add the List<PersonPicture> to the property named "picture" in it and base this via the ID since they have the same?
Any help would be appreciated.
You can use an anonymous object for this, below an example:
List<PersonPicture> pictures = LoadPictures();
List<Person> persons = LoadPersons();
var result = persons.Select(pers => new
{
Id = pers.Id,
Name = pers.Name,
Picture = pictures.Where(pic => pic.PersId == pers.Id)
.FirstOrDefault()
.Thumbnail
};
Another solution is to use a Join:
var result = persons.Join(pictures,
pers => pers.Id,
pic => pic.PersId,
(pers, pic) => {
return new
{
Id = pers.Id,
Name = pers.Name,
Picture = pic.Thumbnail
};
});
LINQ isn't quite designed for modifying existing collections like this, but you can do it:
foreach (tup in people
.Join(
picture,
person => person.ID,
picture => picture.ID,
Tuple.Create
))
{
tup.Item1.Picture = tup.Item2;
}
EDIT: Note that this will produce unpredictable results if a person has more than one picture. Is this a possibility, and how should it be dealt with?
You could either use a Join or the Zip operator in linq. These links will take you to questions about the syntax of using both of them. Basically the Join just adds the two lists together based on a key just like in SQL and the Zip merges the two lists by matching the position of each element in each list..
You want to join the two lists based on a shared key -- the ID.
Basically, you want to use the Join operator in LINQ to find pairs of Person and PersonPicture that match the same ID:
persons.Join(pictures, // join these two lists
person => person.Id, // extract key from person
personPicture => personPicture.PersonId, // extract key from picture
(person, personPicture) => ??? // do something with each matching pair
The question you now face is what to do with each matching pair; Join lets you supply a delegate that takes a matching pair and returns something else, and the result of the Join operation will be a list of those 'something else's produced from each of the matching pairs.
Your problem is that you want to take each pair and do something with it -- specifically, you want to copy the picture from the PersonPicture object to the Person object. Since LINQ is all about finding data but not modifying it, this is not trivial.
You can do this in two ways. One is to create a temporary object from each pair, and then iterate over that and do your thing:
var pairs = persons.Join(pictures,
person => person.Id,
personPicture => personPicture.PersonId,
(person, personPicture) => new { person, personPicture };
foreach (var pair in pairs)
pair.person.Picture = pair.personPicture.Thumbnail;
(You can use a Tuple instead of a temporary object, as was suggested in another answer).
This works, but seems clumsy because of the temporary object (be it an anonymous object or a tuple).
Alternatively, you can do the assignment right inside the delegate, and return the Person object itself, since you're done with the PersonPicture object:
var personsWithPicturesPopulated = persons.Join(pictures,
person => person.Id,
personPicture => personPicture.PersonId,
(person, personPicture) => {
person.Picture = personPicture.Thumbnail;
return person;
});
This has the added bonus of giving you the list of persons for which you found a match in the personPictures list, omitting the ones without a match; this is sometimes exactly what you need (and other times it isn't, in which case you can discard the result of the join).

Reproduce a "DELETE NOT IN" SQL Statement via LINQ/Subsonic

I want to do something like DELETE FROM TABLE WHERE ID NOT IN (1,2,3) AND PAGEID = 9
I have a List of IDS but that could be changed if needs be. I can't work out how to get a boolean result for the LINQ parser.
Here is what Subsonic expects I think.
db.Delete(content => content.PageID == ID).Execute();
I can't work out how to do the NOT IN statement. I've tried the List.Contains method but something not quite right.
UPDATE: One alternative is to do:
var items = TABLE.Find(x => x.PageID == ID)'
foreach(var item in items)
{
item.Delete();
}
This hits the database a lot more though
When you say "something not quite right" what exactly do you mean?
I'd expect to write:
List<int> excluded = new List<int> { 1, 2, 3 };
db.Delete(content => !excluded.Contains(content.PageID)).Execute();
Note that you need to call Contains on the array of excluded values, not on your candidate. In other words, instead of saying "item not in collection" you're saying "collection doesn't contain item."
Try .Contains:
db.Delete(content => content.PageID.Contains(<Array containing ID's>).Execute();
(the above is just an example, might need some polishing for your specific situation)
I have found that this works but its not via LINQ
var table = new WebPageContentTable(_db.DataProvider);
var g = new SubSonic.Query.Delete<WebPageContent(_db.DataProvider)
.From(table)
.Where(table.ID)
.NotIn(usedID)
.Execute();
I have found that this does work and via LINQ - however it hits the database multiple times.
var f = WebPageContent.Find(x => !usedID.Any(e => e == x.ID));
if (f.Count > 0)
{
var repo = WebPageContent.GetRepo();
repo.Delete(f);
}
This I imagine would work in one hit to the database but I get an exception thrown in QueryVisitor::VisitUnary
WebPageContent.Delete(x => !usedID.Any(e => e == x.ID));

Resources