I'm new in linq and i have a simple problem.
i must count how many books have user.
i know its easy but i cant do this.
//database
public List<UserViewModel> GetAllUsers()
{
var result = from u in databaseContext.User
select new UserViewModel
{
UserId = u.UserId,
LastName = u.LastName,
FirstName = u.FirstName,
BirthDate = u.BirthDate,
Email = u.Email,
Phone = u.Phone,
AddDate = u.AddDate,
ModifiedDate = u.ModifiedDate,
IsActive = u.IsActive,
};
return result.ToList();
}
how to do this?
In your model it seems that every Borrow has exactly one Book associated with it. If that is the case and the books cannot be taken more than once (which should be also correct) then all you need to do is:
int count = context.Users.First(x=>x.UserId = 1).Borrow.Count();
This way you can count all the Borrows of a given user supposing that they are all associated with a book.
If two borrows can have the same book than you should slightly rewrite this query to this:
int count = db.Borrow.Where(x => x.UserID== 1).Select(x => x.BookId).Distinct().Count();
This way you will get only the unique books borrowed from the user with id of 1.
To count only the unique books that are not returned use this:
int count = db.Borrow.Where(x => x.UserID== 1 && x.IsReturned == false).Select(x => x.BookId).Distinct().Count();
Related
This has stumped me for the last 3 hours... I'm probably just tired but can't seem to get the logic correct. Would I'd like to do is;
get a list of survey topics and a list of rated survey topics.
if none of the topics have been rated, return the first to the user to rate.
if they've all been rated, return a view saying 'yay you completed the survey'
else identify which ones have not been rated and serve those up in a view.
All topics are served up 1 at a time, each time the topic is rated, its saved then i redirect them back to this controller.
I think my string.equals is not working but can't seem to figure out why. The controller just keeps serving up the same topic. (I'm assuming its the first record that matches vs the one that doesn't?)
public ActionResult Index(string page)
{
Rating rating = new Rating();
var surveyItems = (from s in db.Surveys
where s.Category.Name.Equals(page)
select s).ToList();
var ratedItems = (from r in db.Ratings
where r.Category.Equals(page) && r.UserName.Equals(User.Identity.Name)
select r).ToList();
if (ratedItems.Count() == 0 && surveyItems.Count() > 0)
{
ViewBag.Remaining = surveyItems.Count();
rating.Topic = surveyItems.Select(si => si.Topic).FirstOrDefault();
rating.Category = page;
return View(rating);
}
else if (ratedItems.Count() > 0 && ratedItems.Count() == surveyItems.Count())
{
return View("Finished");
}
else
{
foreach (var si in surveyItems)
{
foreach (var ri in ratedItems)
{
if (!si.Topic.Equals(ri.Topic))
{
rating.Topic = si.Topic;
rating.Category = page;
ViewBag.Total = surveyItems.Count();
ViewBag.Remaining = ViewBag.Total - ratedItems.Count();
return View(rating);
}
}
}
}
Firstly, to answer your question directly, your inner loop will always fail because the 2 lists are not ordered AND theres no gaurantee that item 1 in each list will be the same. Even if they are, the second item from the first list will not equal the first item from the second list (inner loop).
Best bet is to tackle this entirely with LINQ, and while the query is a little difficult to read, the code is a lot cleaner.
var rating = (from s in db.Surveys
join r in db.Ratingson s.Topic equals r.Topic into rated
from ri in rated.Where(x => x.Username == User.Identity.Name).DefaultIfEmpty()
where s.Category.Name.Equals(page) && ri.Topic == null
select new RatingViewModel {Topic = s.Topic, Category = s.Category, Total = db.SurveyItems.Count(), Rated = rated.Count()}).FirstOrDefault();
if (rating == null)
{
return View("Finished");
}
return View(rating);
The LINQ query is essentially the equivalent of the following SQL (give or take)
SELECT * FROM Surveys s
LEFT OUTER JOIN Ratings r ON s.Topic = r.Topic AND r.Username = 'user'
WHERE r.Topic IS NULL
You'll also note that the query projects to RatingsViewModel, I added this because I noticed you had a few references to ViewBag as well as your Rating entity.
RatingViewModel:
public class RatingViewModel
{
public string Topic { get; set; }
public string Category { get; set; }
public int Total { get; set; }
public int Rated { get; set; }
public int Remaining {
get { return Total - Rated; }
}
}
EDIT
Played around with the query a little more, and this is the closest I could get:
// define the where's here so we can use the IQueryable multiple times in LINQ
var surveys = db.Surveys.Where(x => x.Category.Name.Equals(page));
var ratedItems = db.Ratings.Where(y => y.Username == User.Identity.Name && y.Category.Name.Equals(page));
var rated = ratedItems.Count(); // get the rated count here, otherwise we end up with an exception inside the LINQ query
var surveyTopic =
(from s in surveys
// LEFT OUTER JOIN to ratings
join r in ratedItems on s.Topic equals r.Topic into ratedSurveys
from ri in ratedSurveys.DefaultIfEmpty()
// define variables
let total = surveys.Count()
//let rated = ratedItems.Count() -- this throws a NotSupportedException... which seems odd considering the line above
// get non-rated surveys, in this case the RIGHT side of the join (Ratings) is null if there is no rating
where ri.Topic == null
// projection
select new RatingViewModel
{
Topic = s.Topic,
Category = s.Category,
Rated = rated,
Total = total
}).FirstOrDefault();
return surveyTopic == null ? View("Finished") : View(surveyTopic);
Unfortunately this results in 2 DB queries which I was hoping to avoid, still this should be a little closer to what you are after.
Brent,
It didn't like your solution so I tried to revamp it a bit but it's still not happy. Here's my tweak;
var surveyTopic = (from s in db.Surveys.Where(x => x.Category.Name.Equals(page))
let total = s.Topic.Count()
join r in db.Ratings.Where(y => y.UserName == User.Identity.Name) on s.Topic equals r.Topic
let rated = r.Topic.Count()
where r.Topic == null
select new RatingViewModel
{
Topic = s.Topic,
Category = s.Category.Name,
Rated = rated+1,
Total = total
}).FirstOrDefault();
I have two tables. Person and Cities. Person table has CitiID. Cities has CityID and CityName. I just want to get City Name from table Cities. There is a foreign key between them. I can't find necessary code. (Probably so easy question but i really can't figure out right now and hard to find answer because it's keywords are so general)
public ActionResult Index (int id)
{
var personInfo = db.Person.FirstOrDefault(x => x.PersonID == id);
var person = new PersonVM(); // This is my model view.
person.Name = personInfo.Name; // OK
person.Surname = personInfo.Surname; // OK
person.CityName = ??? // personInfo.Cities.???
return View(person);
}
Wow. I found two solution. I couldn't find them before because they are so easy than i guess:
var person = new PersonVM(){CityName = personInfo.Cities.CityName};
or
person.CityName = personInfo.Cities.CityName
I'm quite new to linq, so please bear with me.
I'm working on a asp.net webpage and I want to add a "search function" (textbox where user inputs name or surname or both or just parts of it and gets back all related information). I have two tables ("Person" and "Application") and I want to display some columns from Person (name and surname) and some from Application (score, position,...). I know how I could do it using sql, but I want to learn more about linq and thus I want to do it using linq.
For now I got two main ideas:
1.)
var person = dataContext.GetTable<Person>();
var application = dataContext.GetTable<Application>();
var p1 = from p in Person
where(p.Name.Contains(tokens[0]) || p.Surname.Contains(tokens[1]))
select new {Id = p.Id, Name = p.Name, Surname = p.Surname}; //or maybe without this line
//I don't know how to do the following properly
var result = from a in Application
where a.FK_Application.Equals(index) //just to get the "right" type of application
//this is not right, but I don't know how to do it better
join p1
on p1.Id == a.FK_Person
2.) The other idea is just to go through "Application" and instead of "join p1 ..." to use
var result = from a in Application
where a.FK_Application.Equals(index) //just to get the "right" type of application
join p from Person
on p.Id == a.FK_Person
where p.Name.Contains(tokens[0]) || p.Surname.Contains(tokens[1])
I think that first idea is better for queries without the first "where" condition, which I also intended to use. Regardless of what is better (faster), I still don't know how to do it using linq. Also in the end I wanted to display / select just some parts (columns) of the result (joined tables + filtering conditions).
I really want to know how to do such things using linq as I'll be dealing also with some similar problems with local data, where I can use only linq.
Could somebody please explain me how to do it, I spent days trying to figure it out and searching on the Internet for answers.
var result = from a in dataContext.Applications
join p in dataContext.Persons
on p.Id equals a.FK_Person
where (p.Name.Contains("blah") || p.Surname.Contains("foo")) && a.FK_Application == index
select new { Id = p.Id, Name = p.Name, Surname = p.Surname, a.Score, a.Position };
Well as Odrahn pointed out, this will give you flat results, with possibly many rows for a single person, since a person could join on multiple applications that all have the same FK. Here's a way to search all the right people, and then add on the relevant application to the results:
var p1 = from p in dataContext.Persons
where(p.Name.Contains(tokens[0]) || p.Surname.Contains(tokens[1]))
select new {
Id = p.Id, Name = p.Name, Surname = p.Surname,
BestApplication = dataContext.Applications.FirstOrDefault(a => a.FK_Application == index /* && ???? */);
};
Sorry - it looks like this second query will result in a roundtrip per person, so it clearly won't be scalable. I assumed L2S would handle it better.
In order to answer this properly, I need to know if Application and Person are directly related (i.e. does Person have many Applications)? From reading your post, I'm assuming that they are because Application seems to have a foreign key to person.
If so, then you could create a custom PersonModel which will be populated by the fields you need from the different entities like this:
class PersonModel
{
string Name { get; set; }
string Surname { get; set; }
List<int> Scores { get; set; }
List<int> Positions { get; set; }
}
Then to populate it, you'd do the following:
// Select the correct person based on Name and Surname inputs
var person = dataContext.Persons.Where(p => p.Name.Contains("firstname") || p.Name.Contains("surname")).FirstOrDefault();
// Get the first person we find (note, there may be many - do you need to account for this?)
if (person != null)
{
var scores = new List<int>();
var positions = new List<int>();
scores.AddRange(person.Applications.Select(i => i.Score);
positions.AddRange(person.Applications.Select(i => i.Position);
var personModel = new PersonModel
{
Name = person.Name,
Surname = person.Surname,
Scores = scores,
Positions = positions
};
}
Because of your relationship between Person and Application, where a person can have many applications, I've had to account for the possibility of there being many scores and positions (hence the List).
Also note that I've used lambda expressions instead of plain linqToSql for simple selecting so that you can visualise easily what's going on.
I have the following code which adapts linq entities to my Domain objects:
return from g in DBContext.Gigs
select new DO.Gig
{
ID = g.ID,
Name = g.Name,
Description = g.Description,
StartDate = g.Date,
EndDate = g.EndDate,
IsDeleted = g.IsDeleted,
Created = g.Created,
TicketPrice = g.TicketPrice
};
This works very nicely.
However I now want to populate a domain object Venue object and add it to the gig in the same statement. Heres my attempt....
return from g in DBContext.Gigs
join venue in DBContext.Venues on g.VenueID equals venue.ID
select new DO.Gig
{
ID = g.ID,
Name = g.Name,
Description = g.Description,
StartDate = g.Date,
EndDate = g.EndDate,
IsDeleted = g.IsDeleted,
Created = g.Created,
TicketPrice = g.TicketPrice,
Venue = from v in DBContext.Venues
where v.ID == g.VenueID
select new DO.Venue
{
ID = v.ID,
Name = v.Name,
Address = v.Address,
Telephone = v.Telephone,
URL = v.Website
}
};
However this doesnt compile!!!
Is it possible to adapt children objects using the "select new" approach?
What am I doing so very very wrong?
Your inner LINQ query returns several objects, not just one. You want to wrap it with a call like:
Venue = (from v in DBContext.Venues
where v.ID == g.VenueID
select new DO.Venue
{
ID = v.ID,
Name = v.Name,
Address = v.Address,
Telephone = v.Telephone,
URL = v.Website
}).SingleOrDefault()
Your choice of Single() vs. SingleOrDefault() vs. First() vs. FirstOrDefault() depends on what kind of query it is, but I'm guessing you want one of the first two. (The "OrDefault" variants return null if the query has no data; the others throw.)
I also agree with Mike that a join might be more in line with what you wanted, if there's a singular relationship involved.
Why are you doing a join and a sub select? You can just use the results of your join in the creation of a new Venue. Be aware that if there is not a one to one relationship between gigs and venues you could run into trouble.
Try this:
return from g in DBContext.Gigs
join venue in DBContext.Venues on g.VenueID equals venue.ID
select new DO.Gig { ID = g.ID, Name = g.Name, Description = g.Description,
StartDate = g.Date, EndDate = g.EndDate, IsDeleted = g.IsDeleted,
Created = g.Created, TicketPrice = g.TicketPrice,
Venue = new DO.Venue { ID = venue.ID, Name = venue.Name,
Address = venue.Address, Telephone = v.Telephone,
URL = v.Website }
I have a rather simple scenario where I have two tables in which I want to add data. They are managed with primary key/foreign key. I want to add new data into TABLE A and then retrieve the Id and insert into TABLE B.
I can certainly do it with a stored procedure, but I'm looking at trying to do it using Linq.
What is the best approach ?
I can certainly get the ID and do two separate inserts but that doesn't certainly seem to be a very good way of doing things.
db.Table.InsertOnSubmit(dbObject);
db.SubmitChanges();
Int32 id = dbOject.Id;
//Rest of the code
Any way to elegantly do this?
Do you have the relationship defined between the 2 tables in the object relational designed? If so, you can have linq take care of assigning the ID property of the second table automatically.
Example...
Table A – Order
OrderId
OrderDate
Table B – Order Item
OrderItemId
OrderId
ItemId
Code (Using LINQ-to-SQL):
Order order = new Order();
Order.OrderDate = DateTime.Now();
dataContext.InsertOnSubmit(order);
OrderItem item1 = new OrderItem();
Item1.ItemId = 123;
//Note: We set the Order property, which is an Order object
// We do not set the OrderId property
// LINQ will know to use the Id that is assigned from the order above
Item1.Order = order;
dataContext.InsertOnSubmit(item1);
dataContext.SubmitChanges();
hi i insert data into three table using this code
Product_Table AddProducttbl = new Product_Table();
Product_Company Companytbl = new Product_Company();
Product_Category Categorytbl = new Product_Category();
// genrate product id's
long Productid = (from p in Accountdc.Product_Tables
select p.Product_ID ).FirstOrDefault();
if (Productid == 0)
Productid++;
else
Productid = (from lng in Accountdc.Product_Tables
select lng.Product_ID ).Max() + 1;
try
{
AddProducttbl.Product_ID = Productid;
AddProducttbl.Product_Name = Request.Form["ProductName"];
AddProducttbl.Reorder_Label = Request.Form["ReorderLevel"];
AddProducttbl.Unit = Convert.ToDecimal(Request.Form["Unit"]);
AddProducttbl.Selling_Price = Convert.ToDecimal(Request.Form["Selling_Price"]);
AddProducttbl.MRP = Convert.ToDecimal(Request.Form["MRP"]);
// Accountdc.Product_Tables.InsertOnSubmit(AddProducttbl );
// genrate category id's
long Companyid = (from c in Accountdc.Product_Companies
select c.Product_Company_ID).FirstOrDefault();
if (Companyid == 0)
Companyid++;
else
Companyid = (from Ct in Accountdc.Product_Companies
select Ct.Product_Company_ID).Max() + 1;
Companytbl.Product_Company_ID = Companyid;
Companytbl.Product_Company_Name = Request.Form["Company"];
AddProducttbl.Product_Company = Companytbl;
//Genrate Category id's
long Categoryid = (from ct in Accountdc.Product_Categories
select ct.Product_Category_ID).FirstOrDefault();
if (Categoryid == 0)
Categoryid++;
else
Categoryid = (from Ct in Accountdc.Product_Categories
select Ct.Product_Category_ID).Max() + 1;
Categorytbl.Product_Category_ID = Categoryid;
Categorytbl.Product_Category_Name = Request.Form["Category"];
AddProducttbl.Product_Category = Categorytbl;
Accountdc.Product_Tables.InsertOnSubmit(AddProducttbl);
Accountdc.SubmitChanges();
}
catch
{
ViewData["submit Error"] = "No Product Submit";
}