How to create this lambda expression? - asp.net-mvc

To keep things simple, I have this class:
public class Contact
{
public string Name { get; set; }
public string[] Emails { get; set; }
}
I have a collection of contacts = IEnumerable<Contact>
I need to find all contacts in that collection that have, let's say a text "xxx" in their email addresses (they may have multiple emails).
Something like that doesn't work of course:
var found = contacts.Where(c => c.Emails.Where(e => e.Contains("xxx")));
I am wondering how to build such query using lambda expression?
Thanks.

Use Any instead of Where in the inner expression:
var found = contacts.Where(c => c.Emails.Any(e => e.Contains("xxx")));

Try this
var found = contacts.Where(c => c.Emails.Where(e => e.Contains("xxx")).Count() > 0);
This will return all the contacts according to the specified email condition.
Good Luck !!

Related

A specified Include path is not valid. The EntityType does not declare a navigation property with the name

The code I have below works. It's pulls in a list of every item in my One Repository.
When I add my second table to pull all the items out of THAT table I get the following error, on my DataTwo I can't figure out why it's throwing this error as the first one is programmed the exact same way.
"A specified Include path is not valid. The EntityType does not declare a navigation property with the name"
View Model
public IList<OneVM> Ones { get; set; }
public IList<TwoVM> Twos { get; set; }
public ViewModelVM()
{
this.Ones = new List<OneVM>();
this.Twos = new List<TwoVM>();
}
Working Original Code Below (Controller)
public ActionResult Directory()
{
var vm = new ViewModelVM();
var datas = _OneRepository.GetData();
vm.Datas = _mapper.Map<IList<DataVM>>(datas.OrderBy(i => i.Name));
return View(vm);
}
Desired Broken Code Below (Controller)
public ActionResult Directory()
{
var vm = new FormDirectoryVM();
var datas = _OneRepository.GetData();
var datasTwo= _TwoRepository.GetMoreData();
vm.Datas = _mapper.Map<IList<DataVM>>(datas.OrderBy(i => i.Name));
return View(vm);
vm.DatasTwo= _mapper.Map<IList<DataTwoVM>>(datasTwo);
return View(vm);
}
The problem was my Repository. I was including something that didn't need to be.
public IEnumerable<Two> GetMoreData()
{
return _context.Twos
.Include(i => i.Title) // I don't need this line
.Include(i => i.Description) // I don't need this line either
.Include(i => i.Keywords)
.Include(j => j.Text) // Or this Line
.Where(i => !i.IsDeleted)
;
}

How do I take last n elements from nested collection

I am buinding a chat for an application, so when a user logs in I need to send them all 'unseen' messages, I am using entityframework, Id like to return only the last 20 unseen messages. but my query is not working, currently I get this exception
Count must be a DbConstantExpression or a DbParameterReferenceExpression
what am I doing wrong?
List<ChatVM> unSeenChats = db.Chats.Where(chat => !chat.Seen)
.Select(chat => new ChatVM
{
Id = chat.Id,
IsAnnonymous = chat.IsAnnonymous,
UserName = chat.UserName,
Messages = chat.Messages
.OrderBy(x => x.DateTime)
.Skip(chat.Messages.Count - 20 > 0
? chat.Messages.Count - 20
: 0)
.Take(20)
.Select(message => new MessageVM
{
Id = message.Id,
DateTime = message.DateTime,
Text = message.Text
}).ToList()
}).ToList();
my models are as follows:
public class Chat
{
...
public virtual ICollection<Message> Messages { get; set; }
}
public class Message
{
...
public int ChatId { get; set; }
public virtual Chat Chat { get; set; }
}
public class Entities : IdentityDbContext<ApplicationUser>
{
....
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
...
modelBuilder.Entity<Message>()
.HasRequired(p => p.Chat).WithMany(p => p.Messages).WillCascadeOnDelete(true);
}
}
thanks
I don't think you're allowed to use .Count from within the query (hence the error that you're seeing). In any case, I think you're looking at this from the wrong perspective. You should probably be using the OrderByDescending method, and then just grab the first 20 posts from there.
Something like this:
List<ChatVM> unSeenChats = db.Chats.Where(chat => !chat.Seen)
.Select(chat => new ChatVM
{
Id = chat.Id,
IsAnnonymous = chat.IsAnnonymous,
UserName = chat.UserName,
Messages = chat.Messages
.OrderByDescending(x => x.DateTime)
.Take(20)
.Select(message => new MessageVM
{
Id = message.Id,
DateTime = message.DateTime,
Text = message.Text
}).ToList()
}).ToList();

How to create and related multiple node to another node

Imagine these classes in C#:
public class User
{
public int Id { get; set; }
public string Username { get; set; }
}
public class Post
{
public int Id { get; set; }
public string Text { get; set; }
public string[] HashTags { get; set; }
}
each user can add a post and the relation between them would be the Author, each post could have an array of hash-tags which each of them is going to be a separate node in graph.
when i am going to save each post, I would find the user in grph, create a post node and relate them with a Author Relationship.
the Question is how can I create and relate each hashTag to the post in the same query. (to be inside a transaction).
How could I dynamically add item to query to create it.
the problem is that it could not create node and the relation in one line of create.
Here is what I have tried so far:
var cypherQuery = Db.Instance.Cypher
.Match("(user:User)")
.Where((User user) => user.Username == "XYZ")
.Create("user-[:Author]->(post:Post {newPost})")
.WithParam("newPost", new Post() {Id = 1, Text = "Here is my post about #someHashTag"});
//How to relate this node to the number of hashTags in Post Object???
cypherQuery.ExecuteWithoutResults();
is it good to be in single query or should i divide it in multiple round trips.
I Have tried something with foeach but it seams that the post does not have any value inside the foreach loop:
I have tried something like this:
var cypherCommand = Db.Instance.Cypher
.Match("(user:User)")
.Where((User user) => user.Username == "farvashani")
.Create("user-[:Author]->(post:Post {newPost})")
.WithParam("newPost", "here is my post about #Tag1 and Tag2")
.ForEach(#"(hashtag in {hashTags}|
MERGE post-[:Mentioned]->(hash:HashTag {Text: hashtag}))")
.WithParam("hashTags", new string[] {"Tag1", "Tag2"});
cypherCommand.ExecuteWithoutResults();
In my opinion, i think you have to pre-process the Text property first.
String text = ""Here is my post about #someHashTag""; // For example
List<String> hashTags = new List<String>();
int cnt = 0;
foreach (Match match in Regex.Matches(text, #"(?<!\w)#\w+"))
{
hashTags.Add(match.Value);
}
Then create new instance of Post:
Post newPost = new Post
{
Id = 1,
Text = "Here is my post about #someHashTag",
hashTags = hashTags
};
So, you can use this Cypher:
var cypherCommand = Db.Instance.Cypher
.Match("(user:User)")
.Where((User user) => user.Username == "farvashani")
.Create("user-[:Author]->(post:Post {newPost})")
.WithParam(new {newPost}).ExecuteWithoutResults();
Hope this help.
P/s: Could I ask you a question? Do you think it is better for you to retrieve the separated graph if you use each hashTag as a label of Post? newPost:someHashTag for example?

Neo4jClient: How to deserialize a collect result to a c# class

I have a query where I want only Id and name of the collection back to reduce the network traffic. I am able to get what i want from the database with the following part of the query
ShipToCities = Return.As<IEnumerable<string>>("COLLECT( [shipTo.InternalId, shipTo.Name])")
but the issue is i get back the data like this:
[ [ "IN.KA.MANG", "Mangalore" ], [ "IN.KA.MANG", "Mangalore" ], [ "IN.KA.BANG", "Bangalore" ] ]
but how can I map it to a C# object like
public class CityFound
{
public string CityId { get; set; }
public string CityName { get; set; }
}
is there a way to use some converter to achieve this without me having to use some ugly string manipulation myself?
UPDATE 1:
Actually my query is fairly complex and only way to get the data that I can think of is to handcraft the query like below to reduce the :
//selectedLoadQuery below is a complex query based on user selection...
var query = selectedLoadQuery
.Match("(load)-[:SHIPPED_BY]->(shipper)-[r:HAS_TRANSPORTER]->(transporter)")
.With("load, transporter, shipper, user, count(DISTINCT r) as MyClients")
.Match("p=(shipFrom:City)<-[:SHIP_FROM_CITY]-(load)-[:SHIP_TO_CITY]->(shipTo:City)")
.With("p, load, shipFrom, shipTo, transporter, MyClients")
.Return((load, shipFrom, shipTo) => new
{
TotalShipments = load.CountDistinct(),
FromMyClients = Return.As<long>("MyClients"),
ShipFromCities = Return.As<IEnumerable<string>>("COLLECT( [shipFrom.InternalId, shipFrom.Name])"),
ShipToCities = Return.As<IEnumerable<string>>("COLLECT( [shipTo.InternalId, shipTo.Name])"),
});
Regards
Kiran
You don't need to get so creative. You're only getting into this issue because you're hand crafting such a complex query that flattens out the structure of the data.
Create a class that describes what's in the node:
public class ShippingDestination
{
public long InternalId { get; set; }
public string Name { get; set; }
}
Use this to light up the following syntax in your Return statement:
var cities = graphClient
.Match(...)
.Return(shipTo => new {
Id = shipTo.As<ShippingDestination>().InternalId,
Name = shipTo.As<ShippingDestination>().Name,
})
.Results;

selecting multiple columns and looping through the selected rows

I want to be able to select multiple columns and loop through the retrieved rows and store the selected fields in a string.
Something like select a.firstname, a.lastname from customer where a.id = '123' and loop through the retireved rows and have them write to a string like
FirstName = John; LastName = Doe
FirstName = Steve; LastName = Smith
I have linq statement as
IList<string> strgradeandbatch = new List<string>();
strgradeandbatch = context.GradeAndBatches
.Where(T => T.RequestGuid == request.ItemGuid)
.Select(T => new{T.GradeName, T.Batch}).ToList();
Obviously this is wrong, and not sure how to do it.Thanks for your help in advance
I think you are almost correct. Just remove IList<string> strgradeandbatch = new List<string>() and use anonymous type var strgradeandbatch.
string GradeName, Batch;
var strgradeandbatch = context.GradeAndBatches
.Where(T => T.RequestGuid == request.ItemGuid)
.Select(T => new{T.GradeName, T.Batch}).ToList();
foreach(var item in strgradeandbatch)
{
GradeName = item.GradeName;
Batch = item.Batch;
}
(Note:If you use anonymous type, you can't return this value from the method)
The Select method projects the query results into a list of an anonymous type objects, so it can be used with a list for strings.
One solution is to create a new class
public class Grade
{
public string GradeName {get; set;}
public string Batch {get; set;}
}
Which is going to be used with the Select method
var strgradeandbatch = context.GradeAndBatches
.Where(T => T.RequestGuid == request.ItemGuid)
.Select(T => new Grade
{
GradeName = T.GradeName,
Batch = T.Batch
}).ToList();

Resources