linq group messages show only last ones as whats app do - linq

I want to do a whats app style chat app.
So, I have a message table as columns like
senderName, receiverName, message, messageTime
and I have Users table as columns like
ID, UserName
I want to show whats app style window that shows last messages with names.
So user can click it and see all messages from this user.
For example
John
Hi, Iam here. (date)
Gabriel
That was true. (date)
db.Messages
.Where(x => x.senderName == sessionName|| x.receiverName == sessionName).OrderByDescending(x =>
x.Id).ToList()
.GroupBy(m => new { V = m.senderName , V1 = m.receiverName })
.Select(x => x.First());
I have tried this. But this has problems.

The following is a working example of what you are looking for; showing the latest message (by highest id) for a sender for a particular session
void Main()
{
var messages = GetMessages();
var latest = messages
.GroupBy(m => m.SessionName)
.Select(grp => grp.OrderByDescending(g => g.Id).First())
.ToList();
latest.ForEach(l => Console.WriteLine($"{l.SenderName}\r\n{l.MessageText} ({l.SendDate:yyyy/MM/dd HH:mm:ss})"));
}
// Define other methods and classes here
public class Message
{
public int Id { get; set; }
public string SessionName { get; set; }
public string SenderName { get; set; }
public string ReceiverName { get; set; }
public string MessageText { get; set; }
public DateTime SendDate { get; set; }
}
public IEnumerable<Message> GetMessages()
{
return new[]
{
new Message
{
Id = 1,
SessionName = "Savage",
SenderName = "James T. Kirk",
ReceiverName = "Kahn",
MessageText = "Why would a Starfleet admiral ask a three-hundred-year-old frozen man for help?",
SendDate = new DateTime(2320, 5, 19, 15, 0, 0)
},
new Message
{
Id = 2,
SessionName = "Savage",
SenderName = "Kahn",
ReceiverName = "James T. Kirk",
MessageText = "Because I am better.",
SendDate = new DateTime(2320, 5, 19, 15, 0, 10)
},
new Message
{
Id = 3,
SessionName = "Savage",
SenderName = "James T. Kirk",
ReceiverName = "Kahn",
MessageText = "At what?",
SendDate = new DateTime(2320, 5, 19, 15, 0, 20)
},
new Message
{
Id = 4,
SessionName = "Savage",
SenderName = "Kahn",
ReceiverName = "James T. Kirk",
MessageText = "Everything. Alexander Marcus needed to respond to an uncivilized threat in a civilized time, and for that, he needed a warrior's mind - my mind - to design weapons and warships.",
SendDate = new DateTime(2320, 5, 19, 15, 0, 30)
}
};
}

Related

LINQ Query for populating collection inside another collection

I am looking forward to get a linq query for populating list of teachers and their respective divisons.
Here I have 2 classes Teacher and Division which are related by DivisionGroupID - GroupID
public class Teacher
{
public int ID { get; set; }
public string Name { get; set; }
public List<Division> lstDivison {get;set;}
public int DivisionGroupID { get; set; }
}
public class Division
{
public int GroupID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
In main method List of both Teacher and Division will be populated
static void Main(string[] args)
{
Teacher obj = new Teacher { ID = 1, DivisionGroupID = 11, Name = "abcd" };
Teacher obj1 = new Teacher { ID = 2, DivisionGroupID = 12, Name = "efgh" };
List<Teacher> objList = new List<Teacher>();
objList.Add(obj);
objList.Add(obj1);
Division dv = new Division { GroupID = 11 ,Name="Division1",Description="first" };
Division dv1 = new Division { GroupID = 11, Name = "Division2", Description = "second" };
Division dv2 = new Division { GroupID = 11, Name = "Division3", Description = "third" };
Division dv3 = new Division { GroupID = 12, Name = "Division4", Description = "fourth" };
Division dv4 = new Division { GroupID = 12, Name = "Division5", Description = "fifth" };
Division dv5 = new Division { GroupID = 12, Name = "Division6", Description = "sixth" };
List<Division> lstDiv = new List<Division>();
lstDiv.Add(dv);
lstDiv.Add(dv1);
lstDiv.Add(dv2);
lstDiv.Add(dv3);
lstDiv.Add(dv4);
lstDiv.Add(dv5);
}
The requirement here is to get the list of teachers and populate the sublist of divisions each teachers holding. I got the solution based on 2 approaches.
Using sub query approach :
var upd = from teacher in objList
select new Teacher
{
ID = teacher.ID,
Name = teacher.Name,
lstDivison = (from div in lstDiv
where div.GroupID == teacher.DivisionGroupID
select new Division
{
Name = div.Name,
Description = div.Description
}).ToList()
};
Using Foeach loop through Teacher collection(objList) and updating the lstDivision
objList.ForEach(x => x.lstDivison = lstDiv
.Where(y => y.GroupID == x.DivisionGroupID)
.Select(p => new Division { Name = p.Name, Description = p.Description })
.ToList());
Both of these approaches will give me the result. But i am looking forward a better approach in as part of my project requirement which has to improve the query performance. Could you please suggest which is the best approach to handle this situation?
use yours teacher object to populate list of divisions under it. as my understanding that how it was designed class structure.
//populate property in object
objList.ForEach(x => {
x.lstDivison = lstDiv.Where(w=> w.GroupID == x.DivisionGroupID).ToList();
});
objList.Dump();

How to write a Linq that can retrieve all parent table records and total of sub-table record, I mean 'separate' into two parts

Let's say I have two tables, parent table 'P' and sub-table 'S', I usually wrote the Linq like this to get what I want:
var rows = from p in db.P
join s in db.S on p.Id equals s.ParentId into subContent
where (some condition here)
select new{
Id = p.Id,
Title = p.Title
SubContentCount = subContent.Count()
}
It's very simple, but if for some reason I have to pass a parameter into this query when there has one (let's say 'key'), I have to do this (I guess :-):
var rows = from p in db.P
join s in db.S on p.Id equals s.ParentId into subContent
where (some condition here)
select p;
if(!string.IsNullOrEmpty(key)){ // I'm using C#
rows = rows.Where(q => q.Title.Contains(key))
}
And then:
var list = rows.Select(q => new ()
{
Id = q.Id,
Title = q.Title,
subCount = ???.Count()
});
Is that passable to do Linq like this? if so, how?
Thanks for any kind help!
You could create a method that receives a Func<Table, bool>as parameter and use it to filter your dataset:
public static void Main(string[] args)
{
var rows = new List<Table>
{
new Table { Id = 1, Title = "A", SubContent = new [] { "A1" } },
new Table { Id = 2, Title = "B", SubContent = new [] { "B1", "B2" } },
new Table { Id = 3, Title = "C", SubContent = new [] { "C1", "C2", "C3" } },
};
var title = "C";
foreach (var item in Filter(rows, table =>
String.IsNullOrEmpty(title) || table.Title == title))
{
Console.WriteLine(
"Title={0}, SubContent.Length={1}",
item.Title, item.SubContent.Length);
}
}
public static List<Table> Filter(List<Table> original, Func<Table, bool> filter)
{
return original.Where(filter).ToList();
}
public class Table
{
public int Id { get; set; }
public string Title { get; set; }
public string[] SubContent { get; set; }
}
Why not include the filter in the where clause?
where string.IsNullOrEmpty(key) || p.Title.Contains(key)
Quick example in the interactive console:
public class Parent { public int Id {get; set;} public string Title {get; set;} }
public class SubTable { public int Id {get; set;} public int ParentId {get; set;} }
public class Result { public int Id {get; set;} public string Title {get; set;} public int SubContentCount {get; set;} }
var p1 = new Parent() { Id = 1, Title = "Parent_1" };
var p2 = new Parent() { Id = 2, Title = "Parent_2" };
var p3 = new Parent() { Id = 3, Title = "Parent_3" };
var s1_1 = new SubTable() { Id = 11, ParentId = 1 };
var s1_2 = new SubTable() { Id = 12, ParentId = 1 };
var s1_3 = new SubTable() { Id = 13, ParentId = 1 };
var s2_1 = new SubTable() { Id = 21, ParentId = 2 };
var s2_2 = new SubTable() { Id = 22, ParentId = 2 };
var s3_1 = new SubTable() { Id = 31, ParentId = 3 };
var db_P = new List<Parent>() { p1, p2, p3 };
var db_S = new List<SubTable>() { s1_1, s1_2, s1_3, s2_1, s2_2, s3_1 };
public IEnumerable<Result> GetResults(string key = null)
{
var rows = from p in db_P
join s in db_S on p.Id equals s.ParentId into subContent
where string.IsNullOrEmpty(key) || p.Title.Contains(key)
select new Result() {
Id = p.Id,
Title = p.Title,
SubContentCount = subContent.Count()
};
return rows;
}
And example output (formatted onto multiple lines for readability)
> GetResults().ToList()
List<Submission#0.Result>(3) {
Submission#0.Result { Id=1, SubContentCount=3, Title="Parent_1" },
Submission#0.Result { Id=2, SubContentCount=2, Title="Parent_2" },
Submission#0.Result { Id=3, SubContentCount=1, Title="Parent_3" }
}
> GetResults("1").ToList()
List<Submission#0.Result>(1) {
Submission#0.Result { Id=1, SubContentCount=3, Title="Parent_1" }
}
>

In Nest, how do I specify a child document's parent document while indexing?

Product and Company are in a many-to-one child-parent relationship:
[ElasticType(Name = "product", IdProperty = "ProductId")]
internal class Product
{
public int ProductId { get; set; }
public string Title { get; set; }
}
[ElasticType(Name = "company", IdProperty = "CompanyId")]
public class Company
{
public int CompanyId { get; set; }
public string CompanyName { get; set; }
}
In the mapping of Product, I did:
Func<PutMappingDescriptor<Product>, PutMappingDescriptor<Product>> descriptor = m => m
.MapFromAttributes()
.AllField(a => a.Enabled(false))
.SetParent<Company>();
I created a parent and child:
var company = new Company {
CompanyId = 1,
CompanyName = "XYZ Company"
};
var p2 = new Product{
ProductId = 2,
Title = "ABC Product"
};
es.Index(company);
The problem is then, how do I index p2? With only the Index method, I can only do es.Index(p2). But where do I indicate that p2 should be indexed under the parent company?
Basically I wanted a NEST solution to PUT /myindex/product/2?parent=1.
The closest answer I found so far is in https://stackoverflow.com/a/23953742/1124270. But the answer uses bulk inserts like the following where you have a .Parent method in the chaining to specify the parent's ID:
var bulkResponse = _client.Bulk(b => b
.Index<Address>(bd => bd.Object(new Address { Name = "Tel Aviv", Id = 1 }).Index("test"))
.Index<Person>(bd => bd.Index("test").Object(new Person {Id = 5, Address = 1, Name = "Me"}).Parent(1)));
If you are looking for PUT /myindex/product/2?parent=1 request.
You can do this in the NEST in a such way:
var indexResponse = client.Index(p2, descriptor => descriptor
.Parent(company.CompanyId.ToString()));
which generates below request to elasticsearch
StatusCode : 400,
Method : PUT,
Url : http : //localhost:9200/indexname/product/2?parent=1,
Request : {
"productId" : 2,
"title" : "ABC Product"
}

Linq Split properties of Class and assign it to another Custom Class

I have a Complex Situation now and i am terribly stuck. Kindly Let me know if you can share some light to it.
I have a
List Which will have the Following properties
public class Categories
{
public string DisplayName { get; set; }
public string ValueCode { get; set; }
public string Count { get; set; }
}
This will have Values like
Category1/SubCategory1
cat1/sc1
5
Category1/SubCategory2
cat1/sc2
4
Category 2/Subcategory1
cat2/sc1
5
Category 2/Subcategory2
cat2/sc2
23
I created a Custom Class to fill in the values
public class JobCateogry
{
public string DisplayName { get; set; }
public string ValueCode { get; set; }
public string Count { get; set; }
public List<JobCateogry> SubCategories { get; set; }
}
I have to Split the String in the Code Value and assign it to the SubCategory.
Like My Final out of jobCategory would be
Category1
Cat1
9
SubCategory1
sub1
5
SubCateogry2
sub2
4
I tried to Split the string and assign it to the new class in two step first by splitting and then by assiging. But i am sure i am doing it the wrong way, because the moment i split, i loose the count .
var lstCategory = Categories
.Where(i => i.count > 0)
.Select(item => item.valueCode.Split('/')
.Select(k =>(k)).ToList();
List<JobCategories> jobcategories = lstCategory
.Select(item => item.Split(QueryStringConstants.CAT_SEPERATOR.ToCharArray()[0]))
.GroupBy(tokens => tokens[0].Trim(), tokens => tokens[1])
.Select(g => new JobCategories(g.Key, g.DisplayName,g.ToList(),)).ToList();
Can you please help?
A bit weird task
It might not be the best solution and it only works with the two layers :-), and i tried keeping a lot of linq for the fun of it
anyway hope it can get you moving forward.
full code snippet https://gist.github.com/cbpetersen/db698def9a04ebb2abbc
static void Main(string[] args)
{
var cats = new[]
{
new Categories { Count = "5", ValueCode = "cat1/sc1", DisplayName = "Category1/SubCategory1" },
new Categories { Count = "4", ValueCode = "cat1/sc2", DisplayName = "Category1/SubCategory2" },
new Categories { Count = "5", ValueCode = "cat2/sc1", DisplayName = "Category2/Subcategory1" },
new Categories { Count = "23", ValueCode = "cat2/sc2", DisplayName = "Category2/Subcategory2" }
};
var categories = cats.Select(x => x.DisplayName.Split('/')[0]).Distinct();
var list = new List<JobCateogries>();
foreach (var category in categories)
{
var a = new JobCateogries
{
ValueCode = cats.Where(x => x.DisplayName.Split('/')[0] == category)
.Select(x => x.ValueCode.Split('/')[0]).FirstOrDefault(),
DisplayName = category,
SubCategories = cats.Where(x => x.DisplayName.Split('/')[0] == category)
.Select(x => new JobCateogries
{
SubCategories = new List<JobCateogries>(),
Count = x.Count,
DisplayName = x.DisplayName.Split('/')[1],
ValueCode = x.ValueCode.Split('/')[1]
}).ToList(),
};
a.Count = a.SubCategories.Select(x => int.Parse(x.Count)).Sum().ToString();
list.Add(a);
}
list.ForEach(x => Print(x));
Console.ReadKey();
}
public static void Print(JobCateogries category, int indent = 0)
{
var prefix = string.Empty.PadLeft(indent);
Console.WriteLine(prefix + category.DisplayName);
Console.WriteLine(prefix + category.ValueCode);
Console.WriteLine(prefix + category.Count);
category.SubCategories.ForEach(x => Print(x, indent + 4));
}

Nested LINQ query

I'm trying to perform a nested linq query.
public class Sic
{
public int Id { get; set; }
public string Code { get; set; }
}
public class Message
{
public List<Sic> Sics { get; set; }
public int Id { get; set; }
}
List<Message> msgList = new List<Message>();
Message m1 = new Message
{
Id = 0,
Sics = new List<Sic>()
{
new Sic() {Id = 0, Code = "A2A"},
new Sic() {Id = 1, Code = "A2B"},
new Sic() {Id = 2, Code = "A2C"},
new Sic() {Id = 3, Code = "A2D"}
}
};
Message m2 = new Message
{
Id = 1,
Sics = new List<Sic>()
{
new Sic() {Id = 4, Code = "B2A"},
new Sic() {Id = 5, Code = "B2B"},
new Sic() {Id = 6, Code = "B2C"},
new Sic() {Id = 7, Code = "B2D"}
}
};
msgList.Add(m1);
msgList.Add(m2);
List<string> searchList = new List<string> {"A2A", "A2B"};
I want to find messages in msgList where searchList is contained by the Sics of each each message, i.e. m1 should be found using the above searchList.
You can use something like,
msgList.Where(msg=>msg.Sics.Any(sic=>searchList.Contains(sic.Code)));
or if you need to match all search terms,
msgList.Where(msg => searchList.All(searchTerm=>msg.Sics.Any(sic=>sic.Code==searchTerm)))
If all ids in searchlist need to be matched
msgList.Where(msg => searchList.Any() && searchList.All(s => msg.Sics.Any(sic => s==sic.Code)))
If any id in searchlist need to be matched
msgList.Where(msg=>msg.Sics.Any(sic=>searchList.Contains(sic.Code)));

Resources