Entity Framework and Related Table Data - asp.net-mvc

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

Related

Issue in searching a name in entity framework model using code first approach

I have the following code to retrieve a name when a user enters the name in the search box and the function searches the name from Student model. Please find below the code. However, it doesn't show anything.
public Student SearchName(string search)
{
var student = _context.Student.FirstOrDefault(a => a.Name == search);
var student = from a in _context.Student
select a;
if(!String.IsNullOrEmpty(search))
{
student = student.Where(a => a.Name!.Contains(search))
}
return student;
}

Count books of user with Linq-To-Sql

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();

load navigation properties with filter for Entity Framework 4.3

Few days back I put a question regarding mapping two classes Message and MessageStatusHistory using EF. The mapping is going fine but I am facing some problems with the navigation property StatusHistory in class Message that relates it to MessageStatusHistory objects. I am loading the messages for one user only and want to the statuses pertaining to that user only. Like I would want to show if the user has marked message as read/not-read and when. If I use default loading mechanism like following it loads all the history related to the message irrespective of the user:
IDbSet<Message> dbs = _repo.DbSet;
dbs.Include("StatusHistory").Where(x=>x.MessageIdentifier == msgIdentifier);
To filter history for one user only I tried following trick:
IDbSet<Message> dbs = _repo.DbSet;
var q = from m in dbs.Include("StatusHistory")
where m.MessageIdentifier == msgIdentifier
select new Message
{
MessageIdentifier = m.MessageIdentifier,
/*OTHER PROPERTIES*/
StatusHistory = m.StatusHistory
.Where(x => x.UserId == userId).ToList()
};
return q.ToList();//THROWING ERROR ON THIS LINE
I am getting the error:
The entity or complex type 'MyLib.Biz.Message' cannot be constructed in a LINQ
to Entities query.
I have tried by commenting StatusHistory = m.StatusHistory.Where(x => x.UserId == userId).ToList() also but it has not helped.
Please help me in getting Messages with filtered StatusHistory.
EDIT:- above is resolved with this code:
var q = from m in _repository.DBSet.Include("Histories")
where m.MessageIdentifier == id
select new {
m.Id,/*OTHER PROPERTIES*/
Histories = m.Histories.Where(x =>
x.SenderId == userId).ToList()
};
var lst = q.ToList();
return lst.Select(m => new Message{
Id = m.Id, MessageIdentifier = m.MessageIdentifier,
MessageText = m.MessageText, Replies = m.Replies,
ReplyTo = m.ReplyTo, Histories = m.Histories, SenderId =
m.SenderId, SenderName = m.SenderName, CreatedOn = m.CreatedOn
}).ToList();
But if I try to include replies to the message with:
from m in _repository.DBSet.Include("Replies").Include("Histories")
I am getting error on converting query to List with q.ToList() for Histories = m.Histories.Where(x=> x.SenderId == userId).ToList().
About your EDIT part: You cannot use ToList() in a projection, just leave it an IEnumerable<T> and convert to a List<T> when you construct the Message. You also don't need to create two list objects, you can switch from the LINQ to Entities query to LINQ to Objects (the second Select) by using AsEnumerable():
var list = (from m in _repository.DBSet
where m.MessageIdentifier == id
select new {
// ...
Histories = m.Histories.Where(x => x.SenderId == userId)
})
.AsEnumerable() // database query is executed here
.Select(m => new Message {
// ...
Histories = m.Histories.ToList(),
// ...
}).ToList();
return list;
Be aware that Include has no effect when you use a projection with select. You need to make the properties that you want to include part of the projection - as you already did with select new { Histories.....

How to join multiple tables using LINQ-to-SQL?

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.

Entity Framework - Join on many to many

I have a simple many to many relationship and I am wondering how you get data out of it. Here is the setup
Tables
Media
Media_Keyword (many to many map)
Keyword
Here is the code I have:
public List<Keyword> GetFromMedia(int mediaID)
{
var media = (from m in Connection.Data.Media
where m.id == mediaID
select m).First();
var keys = (from k in media.Media_Keyword
select new Keyword {ID = k.Keywords.id, Name = k.Keywords.keyword});
return keys.ToList();
}
Is there a way to do this better?
Usually, I select right from the many-to-many map.
var keys = from k in Connection.Data.Media_Keyword
where k.MediaID == mediaID
select k.Keywords;
I've not used the entity framework specifically, but can't you just combine them like this?
public List<Keyword> GetFromMedia(int mediaID)
{
return (from m in Connection.Data.Media
from k in m.Media_Keyword
where m.id == mediaID
select new Keyword {ID = k.Keywords.id, Name = k.Keywords.keyword}).ToList();
}
Response to Kleinux (Don't know why i can't add a comment to your question)
Sure you can, but it's not necessarly a good things, because context giving you a new "keyword". Then, if you try to update this or something thinking that you will update, context gonna see it as a new keyword and would create a new one instead of updating it.
** UPDATE
Sorry for my english, i'm french, well not french but from Quebec. I'm giving my 110%!!

Resources