Select a single child item from child collection in LINQ - linq

On my LyricRepository.cs I have the following method:
public Lyric GetLyric(string artistSlug, string lyricSlug)
{
var artist = _context.Artists.FirstOrDefault(a => a.Slug == artistSlug);
if (artist == null) return null;
if (artist.Lyrics.Any(l => l.Slug == lyricSlug))
{
return _context.Lyrics.FirstOrDefault(l => l.Slug == lyricSlug);
}
return null;
}
Artist and Lyrics have a one-to-many relationship:
One Artist has many Lyrics
When I get the artist how can I simply return the lyirc that matches the lyricSlug?
What I have now works, but I am making two calls to the database. One to get the artist, then another to get the lyric.

Using FirstOrDefault as you did:
public Lyric GetLyric(string artistSlug, string lyricSlug)
{
var artist = _context.Artists.FirstOrDefault(a => a.Slug == artistSlug);
return artist!=null?artist.Lyrics.FirstOrDefault(l => l.Slug == lyricSlug):null;
}
Now to improve your query you can do the following using the navigation property in one of the conditions:
public Lyric GetLyric(string artistSlug, string lyricSlug)
{
return _context.Lyrics.FirstOrDefault(a => a.Slug==lyricSlug
&& a.Artist.Slug == artistSlug);
}

Related

how to return multiple items from linq query

Hi I have a method which i am calling to get the list of email of users , i am returning that list and my calling method is using these emails , I want to get the program title as well to pass with the list how to achieve that.
public static List<string> GetAllStudents(int? year,int? program,int? module,int? block)
{
var res = (from s in std.Student_courses
join p in std.Programs
on s.Program_Id equals p.Id
join sc in std.Students
on s.Student_id equals sc.Student_Id
where s.Program_Id == program && s.Year_Id == year && s.Module_Id==module && s.Block_Id==block
select new
{
Email = sc.Student_Email,
Program=p.Program_Title
}).ToList();
List<string> EmailList = new List<string>();
foreach (var item in res)
{
EmailList.Add(item.Email);
}
return EmailList;
//var result = from userDistrict in std.Student_courses
// from district in std.Students
// where (userDistrict.Student_id == district.Student_Id)
// select district.Student_Email;
// return std.Student_courses.Where(x => x.Program_Id == program && x.Year_Id == year && x.Module_Id == module && x.Block_Id == block ).ToList();
}
Using new {} creates an anonymous type which cannot be passed to a method or returned out of the method scope (even if it's inside a list).
You are returning a list of string values. I recommend you change this to a list of a new class that contains both the email and the Program properties.
public class EmailInfo
{
public string Email { get; set; }
public string Program { get; set; }
}
You can then return this class from your method:
public static List<EmailInfo> GetAllStudents(int? year, int? program, int? module, int? block)
{
var results =
from s in std.Student_courses
join p in std.Programs on s.Program_Id equals p.Id
join sc in std.Students on s.Student_id equals sc.Student_Id
where s.Program_Id == program && s.Year_Id == year && s.Module_Id == module && s.Block_Id == block
select new EmailInfo
{
Email = sc.Student_Email,
Program = p.Program_Title
};
return results.ToList();
}
And use both values (as an example I've printed the values to the console):
var emails = GetAllStudents();
emails.ForEach(x => Console.WriteLine($"'{x.Email}', '{x.Program}'"));
This could print the following to the console:
'email1#domain.com', 'title 1'
'email2#domain.com', 'title 2'

how to write LINQ Query on three columns with a different value on each one

I'm new to this and this is my first question.
So far I have this, but it takes a long time to get the record:
public string BuscarPedimento(string patente, string pedimento2, string aduana)
{
using (var context = new DataStage3Context())
{
DsPedimentos pedimento = context.DsPedimentos.FirstOrDefault(p => (p.Patente == patente & p.AduanaDespacho == aduana & p.Pedimento == pedimento2));
if (pedimento == null)
return "";
else
return Convert.ToString(pedimento.Id);
}
}

How to get all items with the same value in list of lists c# LINQ?

I have a to add a specific requirement in a piece of code already implemented.
The data structure is something of this sort:
public class Module
{
public string Type;
public string ID;
public List<Point> Points = new List<Point>();
}
public class Point
{
public string Type;
public string Location;
public string Connection;
}
Originally LINQ was used to return all modules which certain characteristics
List<Module> miList = Modules.Where(m => m.Type != null
&& m.ID == "A"
&& m.Points.Where(t => t.Connection == ""
&& SimilarPoint(t.Type, x).ToList())
.Count() > 0)
.ToList();
with x an input to the function. The new requirement dictates that the modules returned shall all have points with Connection equal to "" and the same value in the Location field.
It seemed to me that the SelectMany could be used to this end, but I am not getting what I expected.
How should the function above be modified?
Thanks in advance
Not exactly sure what the SimilarPoint(t.Type, x) does here.
May be you should try something like this and find out if it works for you -
var resultSet = Modules.Where(m => !string.IsNullOrEmpty(m.Type) && m.ID.Equals("A"))
.Select(n =>
new Module {
Type=n.Type,
ID=n.ID,
Points= n.Points.Where(p => String.IsNullOrEmpty(p.Connection) && String.IsNullOrEmpty(p.Location)).ToList()
})
.ToList();
You said all the returned modules have the same Location, but that doesn't explain how you select which Location so I arbitrarily picked the first matching module's location:
var miQuery1 = Modules.Where(m => m.Type != null
&& m.ID == "A"
&& m.Points.Where(t => t.Connection == ""
&& SimilarPoint(t.Type, x).ToList()).Count() > 0)
.Where(m => m.Points.All(p => p.Connection == ""));
var miQuery2 = miQuery1.Where(m => m.Location == miQuery1.First().Location);
List<Module> miList = miQuery2.ToList();

How to create a list of child IDs

In my controller I have a method that receives a decimal value (id).
The objective of this method is to recover a list of old revisions from a database table containing work permits. Each record on this table has a WorkPermitID as a primary key and OldRevisionWorkPermitID referencing the ID of the previous version.
I have no problems when collecting the children IDs (old versions), but it raises an exception indicating that LINQ to Entities does not recognize .ToString() method.
What I'm doing wrong? I know that I need to do without converting to string (WorkPermitID is defined as numeric in the database), but I tried several ways with no success.
public ActionResult GetVersions(decimal id){
var model = new PermisosTrabajoModel();
List<string> ChildIDs = new List<string>();
var WP = OtWeb.WorkPermit.Single(q => q.WorkPermitID == id);
while (WP.OldRevisionWorkPermitID != null)
{
var child = WP.OldRevisionWorkPermitID;
ChildIDs.Add(child.ToString());
WP = OtWeb.WorkPermit.Single(q => q.WorkPermitID == child);
}
model.WPs = OtWeb.WorkPermit
.Where(q => q.DeptID == 1
&& ChildIDs.Contains(q.WorkPermitID.ToString())).ToList();
return View (model);
}
Solution1
If both of your fields are decimal... Don't use ToString(), and use a list of decimal
var model = new PermisosTrabajoModel();
var childIDs = new List<decimal>();
var WP = OtWeb.WorkPermit.Single(q => q.WorkPermitID == id);
while (WP.OldRevisionWorkPermitID != null)
{
childIDs.Add(WP.OldRevisionWorkPermitID);
WP = OtWeb.WorkPermit.Single(q => q.WorkPermitID == child);
}
model.WPs = OtWeb.WorkPermit
.Where(q => q.DeptID == 1
&& childIDs.Contains(q.WorkPermitID)).ToList();
Solution2
In linq2entities, you can use SqlFunctions.StringConvert instead of ToString() for a numeric value.
SqlFunctions.StringConvert(q.WorkPermitId)
instead of
q.WorkPermitID.ToString()
for example

MVC3 Multiple Conditions in where Clause

I have the following in my Controller
var workshop = registerDB.Workshops.Single(w => w.WorkshopID == id);
ViewBag.Enrollments = registerDB.Carts.Where(x => x.Username.Equals(User.Identity.Name));
and this in my view
#{
//var carts = Model.Carts.Where(x => x.Username.Equals(User.Identity.Name));
var carts = ViewBag.Enrollments;
var timeSlot = Model.TimeSlot;
}
#{
foreach (var item in carts)
{
if (item != null)
{
if (timeSlot == item.Workshop.TimeSlot)
{
<h3>#timeSlot</h3>
}
}
else
{
<h3>Does not Exist</h3>
}
}
}
each time ViewBag.Enrollments = registerDB.Carts.Where(x => x.Username.Equals(User.Identity.Name)); returns no results, I get an error saying System.InvalidOperationException: There is already an open DataReader associated with this Command which must be closed first. and this line is highlighted
if (timeSlot == item.Workshop.TimeSlot)
Try calling .ToList() in the controller to eagerly fetch the results:
ViewBag.Enrollments = registerDB
.Carts
.Where(x => x.Username.Equals(User.Identity.Name))
.ToList();
You are checking that item != null but not that item.Workshop != null before trying to use it. It would appear that is perhaps the error, but why it's raising InvalidOperationException rather than NullReferenceException I don't know.
Try:
if (item != null && item.Workshop != null)
{
if (timeSlot == item.Workshop.TimeSlot)
{
<h3>#timeSlot</h3>
}
}
Could you put the single call in your model:
workshops workshop = registerDB.Workshops.Single(w => w.WorkshopID == id);
And then in your controller set the ViewBag:
try
{
ViewBag.Enrollments = workshop.Carts.Where(x => x.Username.Equals(User.Identity.Name));
}
catch
{
ViewBag.Enrollments = "There are no results";
}

Resources