Complex LINQ Queries (Multiple Joins) - asp.net

I'm fairly new to LINQ and I am having a bit of trouble with my query. I am trying to fetch surveys that are associated to particular groups (SurveyGroups table is the assignment table). However, once I return my model to my View I get a null error.
This is what I have so far:
public ActionResult Index()
{
var userID = User.Identity.GetUserId();
var clientID = _db.Users.Where(u => u.Id == userID).Select(u => u.ClientID).FirstOrDefault();
var userGroups = _db.UserGroups.Where(x => x.UserID == userID).ToList();
var groupedSurveys = (from t1 in userGroups
join t2 in _db.SurveyGroups
on t1.GroupID equals t2.GroupID
select new { t2.SurveyID }).ToList();
var surveys = (from t11 in groupedSurveys
join t22 in _db.Surveys.Where(s => s.ClientID == clientID)
on t11.SurveyID equals t22.SurveyID
select new { t22.ClientID, t22.Name}).ToList();
return View("~/Views/User/Dashboard.cshtml", surveys);
}
Firstly, I get the userID.
I get the ClientID associated with that userID.
Then I join userGroups object with the SurveyGroup table.
Lastly, I join groupedSurveys with the Surveys table.
Any guidance would be greatly appreciated!
UPDATED:
The error I am receving is the following:
The model item passed into the dictionary is of type 'System.Collections.Generic.List1[<>f__AnonymousType65[System.Int32,System.Nullable1[System.Int32],System.Nullable1[System.Int32],System.Nullable1[System.Int32],System.String]]', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable1[SM_XPRESS.Models.Survey]'.

In this line:
select new { t22.ClientID, t22.Name}
...you are creating a new instance of an anonymous type, based on the data in t22 (which is a survey record).
However, the list you need to provide to your view needs to be a list of Survey instances, not a list of anonymous type instances.
So change it to
select t22
and you're good to go.

Related

How to get IEnumerable from IQueryable in such cases, where 2 queries are required in ASP.NET MVC?

I have situation like this: in LearningStatuses table I have a composite primary key, made up of CourseCode and UserID.
CourseCode and UserID are also the PK of Course and ApplicationUser tables respectively.
The LearningStatuses table is basically working as a enroll table.
So if a user enroll in a course, his user ID and Course Code will be stored in this table.
Now I want to fetch all the enrolled courses of a particular user in his dashboard.
Firstly I'm looking for the courseCode that is there in the learningSatatuses table with his user ID, and storing it in a list of int.
Now I want the list of courses from the database, of those IDs as an IEnumerable to iterate over them in the view.
public ActionResult Dashboard()
{
string currentUserID = User.Identity.GetUserId();
List<int> CoursesEnrolled = db.LearningStatuses
.Where(l => l.UserID == currentUserID)
.Select(l => l.CourseCode)
.ToList();
List<Course> CoursesEnrolledCourse = new List<Course>();
foreach (int item in CoursesEnrolled)
{
Course c = (Course)db.Courses.Where(c => c.CourseCode == item);
CoursesEnrolledCourse.Add(c);
}
return View();
}
During the 2nd step, I find myself unable to cast this IQueryable to a list anymore.
I've tried few other approaches too. but at the end of it I'm not able to get the desired IEnumerable of course objects for a particular user.
N.B: I have an Identity Framework user table. So my UserID is an alias of ApplicationUserID, that's a string.
What is the right approach to get the expected result.

How to use Linq where condition to check if a list of strings contains any string

I have a LINQ query like this:
var data = from user in _context.Users
select new
{
UserId = user.Id,
Username = user.UserName,
RoleNames = (from userRole in _context.UserRoles
join role in _context.Roles on userRole.RoleId
equals role.Id
where userRole.UserId == user.Id
select role.Name).ToList()
};
if (!string.IsNullOrEmpty(searchText))
data = data.Where(x => x.Username.Contains(searchText) || x.RoleNames.Any(r => r.Contains(searchText)));
The result are something like this:
User Id | Username | RoleNames
1 | Matt | [User, Admin]
2 | Jennifer | [User]
3 | John | []
But the
x.RoleNames.Any(r => r.Contains(searchText))
is not working, it's causing InvalidOperationException: The LINQ expression '...' could not be translated.
I want to pass in a searchText to search for either "Username" and "RoleNames" columns.
E.g. if I pass in searchText = 'Jen' it will return User Id 2, and if I pass in searchText = 'user' it will return User Id 1 and 2.
Any help would be appreciated.
While theoretically it is possible to translate this condition to the SQL, your EF Core version do not supports that. Consider to make filter before defining custom projection:
var users = _context.Users.AsQueryable();
if (!string.IsNullOrEmpty(searchText))
users = users.Where(x => x.Username.Contains(searchText) || x.Roles.Any(r => r.Contains(searchText)));
var data =
from user in users
select new
{
UserId = user.Id,
Username = user.UserName,
RoleNames = (from userRole in _context.UserRoles
join role in _context.Roles on userRole.RoleId
equals role.Id
where userRole.UserId == user.Id
select role.Name).ToList()
};
This may not be the answer you want now but you'll probably look back on this and see it as the right answer later.
Your ORM (Probably Entity Framework) can't translate your Linq Expressions into a query. If your project will have a small database and you don't need your queries to perform well then, tweak your expression so that the ORM can generate a functioning, albeit sub-optimal, query.
If data will be a significant part of your project then switch to a light ORM like Dapper and learn the query language of your database. Write optimal, parameterised queries in that query language and yield the long term benefits.

How to compare two tables data and show only matched data in drop down list

I have two tables student and teacher and i want to compare their school branches and show only matched student in drop down using linq
Below is the code,
var teacher = db.TeacherEnroll.Select(x =>new{x.BranchClassesId,x.SubjectId});
var student = db.EnrollInClass.Select(x => new { x.ClassSubject.ClassesId, x.BranchClassesId });
ViewBag.show = db.EnrollInClass.ToList().Where(x=>student.Equals(teacher));
return View();
query below should give the students that has common branches with teachers
var students =
(from t in db.TeacherEnroll
from s in db.EnrollInClass.Where(s => s.BranchClassedId == t.BranchClassesId)
select s).ToList();

MVC List Not Working as it should

So the issue that I am having is getting the correct db items to work in the search in the web page, for some reason it does not search all of the values from Vehicle_Make that exist in Vehicle_Details - Make_ID is the primary key of Vehicle_Make and it is a FK in Vehicle_Details.
What happens is, it shows all the items on the page in a list, but the search does not work when I search for any of those items.
public class MapController : Controller
{
private GoogleMapEntities db = new GoogleMapEntities();
// GET: Map
public ActionResult Index()
{
GoogleMapEntities GE = new GoogleMapEntities();
List<Vehicle_Details> vehList = db.Vehicle_Details.ToList();
GoogleMapViewModel GMviewmodel = new GoogleMapViewModel();
List<GoogleMapViewModel> GMviewmodelList = vehList.Select(x=> new GoogleMapViewModel {
Make_Name = x.Vehicle_Make.Make_Name,
Make_ID = x.Vehicle_Make.Make_ID,
User_ID = x.User.User_ID,
MapLat = x.User.MapLat,
MapLong = x.User.MapLong
// Dealer_name = x.User.Dealer_name
}).ToList();
return View(GMviewmodelList);
}
[HttpPost]
public ActionResult Search(string Location)
{
GoogleMapEntities GE = new GoogleMapEntities();
////SELECT Make_Name DATA FROM DB1
var result = GE.Vehicle_Make.Where(x => x.Make_Name.StartsWith(Location)).ToList();
var GetVeh = (from vd in db.Vehicle_Details
join vm in db.Vehicle_Make
on vd.Make_ID equals vm.Make_ID
join u in db.User
on vd.User_ID equals u.User_ID
select vm).ToList();
//SELECT ALL ELEMENTS FROM Veh Make TABLE THAT EXISTS ON Veh Details TABLE BASED ON EXISTING ID's
var resultFinal = (from e in result
where !(from m in GetVeh
select m.Make_ID).Contains(e.Make_ID)
select e
).ToList();
return Json(resultFinal, JsonRequestBehavior.AllowGet);
}
}
Another weird thing that happens is, if I add the "!" in the following code, it does return the vehicle makes that do not exist in the vehicle details table but without the "!", it does not search for the values that do exist in both tables.
var resultFinal = (from e in result
where !(from m in GetVeh
select m.Make_ID).Contains(e.Make_ID)
select e
).ToList();
Sample Data:
BMW exists in Vehicle_Make(Make_ID PK) and Vehicle_Details(Make_ID FK).
Vespa exists in Vehicle_Make but not in Vehicle_Details
If I search for BMW it does not work but if I search for Vespa or any vehicle that does not exist in the Vehicle_Details table, it will find those, but not the vehicles that exist in both tables.
Once I get the correct items that need to be searched for like BMW, it must match the Dealerships(Users table) and take the MapLat & MapLong from the "Users" table and then pin point them onto the map.
Vehicle_Details has (User_ID FK) which is the PK of the Users Table.
Basically, Vehicle_Details has Users and Vehicle_Make linked to it, while Users and Vehicle_Make do not have a link in them so therefore vehicle details is the link. Is this possible to make work for what I require?

Entity framework select from two tables with different table relationship primary/foreign key scenarios

I have two sample tables:
SCENARIO 1
TABLE 1 - INGREDIENT
ingredientId(PK, int, not null)
userId(FK, int, not null)
timestamp(datetime, not null)
TABLE 2 - INGREDIENT ADDITIONAL INFORMATION
ingredientAdditionalInformationId(PK, int, not null)
ingredientId(FK, int, not null)
isApproved(bit, not null)
unitsConverted(bit, not null)
SELECT SENTENCE IN CODE BEHIND:
public IQueriable GetIngredientData(int ingredientId)
{
using (var context = new MyEntities())
{
var result = context.Ingredient
.Where(i => i.ingredientId == ingredientId)
.Select(i => new
{
i.ingredientId,
i.userId
i.IngredientAdditionalInformation.FirstOrDefault(iai => iai.ingredientId = i.ingredientId).isApproved
i.IngredientAdditionalInformation.FirstOrDefault(iai => iai.ingredientId = i.ingredientId).unitsConverted
});
return result.ToList().AsQueriable();
}
}
or select with join (I know that you can join with method syntax but I can write join with query method faster)
public IQueriable GetIngredientData(int ingredientId)
{
using (var context = new MyEntities())
{
var result = from i in context.Ingredient
join iai in context.IngredientAdditionalInformation on i.ingredientId equals iai.ingredientId
where i.ingredientId == 1
select new
{
i.ingredientId,
i.userId
iai.isApproved
iai.unitsConverted
};
return result.ToList().AsQueriable();
}
}
Which one is better/faster with join or FirstOrDefault() or I should write database table different like in example 2 below:
SCENARIO 2
TABLE 1 - INGREDIENT
ingredientId(PK, int, not null)
userId(FK, int, not null)
timestamp(datetime, not null)
TABLE 2 - INGREDIENT
ingredientId(PK, FK, int, not null) //WITHOUT PRIMARY (ingredientAdditionalInformationId) AUTO INCREMENT KEY)
isApproved(bit, not null)
unitsConverted(bit, not null)
Because I know that every ingredient have only one additional info...
SELECT SENTENCE IN CODE
using (var context = new MyEntities())
{
var result = context.Ingredient
.Where(i => i.ingredientId = 1)
.Select(i => new
{
i.ingredientId,
i.userId
i.IngredientAdditionalInformation.isApproved
i.IngredientAdditionalInformation.unitsConverted
});
}
I would like to know which table design is better (SCENARIO1 or SCENARIO2) for optimized select, if I really need auto increment key in ingredientAdditionalInformation if I know that there will be only one entry for every Ingredient and if this is the right way to use entity framework?
If you're maintaining a one-to-one relationship between the two tables, then your second design is better, because it will also ensure referential integrity in your database.
You can then make the property a single navigation property in your entity framework model, and simplify your EF query as follows. If you have lazy loading of navigational properties enabled in your model, you may be able to get away without using the include if you're
var result = from i in context.Ingredient.Include("IngredientAdditionalInformation") select i;
And then access the properties as follows:
i.IngredientAdditionalInformation.isApproved
However, do you really need an additional table? With only three properties on each I'd just combine them into one table and then you have all the properties available to you immediately.
Scenario 2 is better since you are saying there is a one-to-one relationship between the two tables.
Another option you should explore is using Table Per Type Inheritance. You will not need to specify eager loading using Include nor joins in this case.
Assuming your table1 = IngredientBase and table2 = Ingredients and in your context you have set up
public IQueryable<Ingredient> Ingredients {
get { return IngredientBases.OfType<Ingredient>(); } }
then you'll just need
using (var context = new MyEntities())
{
var result = context.Ingredients.Where(i => i.ingredientId = 1);
}
SQL wise, the 2nd select of scenario1 and scenario2 will produce nearly equivalent plans. But performance wise, scenario2 will be better, not to mention being the right design for a 1-1 relationship tables.

Resources