MVC List Not Working as it should - asp.net

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?

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.

Datasource Paging Issue (Revised)

A simple testing setup: department: employee, 1:M and a search form that allows filtering on Emploee FirstName =, lastname =, email contains, age >=, join date <= and related department =.
A search form with widgets bound to parameters of a cloud SQL datasource query script.
A Submit button on the search form which opens up a query results page with a table bound to the cloud SQL query script datasource.
query script
var params = query.parameters;
return getEmployeeRecords_(
params.param_FirstName,
params.param_LastName,
params.param_Email,
params.param_StartDate,
params.param_Age,
params.param_Department
);
and
function getEmployeeRecords_( firstName, lastName, email, startDate, age,
department) {
var ds = app.models.Employee.newQuery();
if ( firstName !== null ) {
ds.filters.FirstName._equals = firstName;
}
if ( lastName !== null ) {
ds.filters.LastName._equals = lastName;
}
if ( email !== null) {
ds.filters.Email._contains = email;
}
if ( startDate !== null) {
ds.filters.StartDate._greaterThanOrEquals = startDate;
}
if ( age !== null) {
ds.filters.Age._lessThanOrEquals = parseInt(age, 10);
}
if ( department !== null) {
ds.filters.Department.Department._equals = department;
}
var records = ds.run();
// intention is to store this value for future use
var recs = records.length;
return records;
}
On the results page for the query script datasource paging is just broken. A query that correctly returns 8 records where the query page size is set to 5 allows me to get the pager to go to page 1000 if I wished, but the datasource always stays on the first page of records. With page size set to e.g., 100 the correct result set is clearly displayed.
In fact everything I do with this sort of query has paging issues. If I insert this code
var ds = app.models.Employee.newQuery();
//ds.filters.FirstName._equals = firstName;
//ds.filters.LastName._equals = lastName;
//ds.filters.Email._contains = '.com';
//ds.filters.StartDate._greaterThanOrEquals = startDate;
ds.filters.Age._lessThanOrEquals = 40;
//ds.filters.Department.Department._equals = department;
ds.sorting.Age._ascending();
var records = ds.run();
return records;
directly into the datasource query script I still have similar paging issues.
If I use a query builder script such as
(
FirstName =? :param_FirstName and
LastName =? :param_LastName and
Email contains? :param_Email and
StartDate >=? :param_Startdate and
Age <=? :param_Age and
Department.Department =? :param_Department
)
and bindings such as
#datasources.Search_Query_Builder.query.parameters.param_FirstName
this works without issue. The same with direct filtering, where we use bindings such as
#datasources.Employee.query.filters.FirstName._equals
Anyone any ideas in terms of what is wrong with this stuff. We need query scripts for more controle, e.g., the ability to retrieve a count of records and where you have to filter for a condition where you restrict data, e.g. a logged in user is related to a client which in turn is related to a property and the property value is restricted according to client.
... Just looking at a real application under development and the use of a query script within the datasource query script editor, no parameters, no binding, just this code:-
var ds = app.models.Incident.newQuery();
ds.filters.Id._greaterThanOrEquals = 200;
ds.filters.Id._lessThanOrEquals = 300;
var records = ds.run();
return records;
and a page size set to 20 and again the paging is up the creek, never moves beyond the first page of records despite the page number incrementing.
I have some suggestions how to address this issue, although it is still unclear what exactly is causing the paging issue and whether or not my suggestions will fix the underlying issue. However, in my own application environment I have several instances where I use a standard SQL model and I apply filters to a datasource from that model and then have a concurrent calculated model (datasource) that returns the total count of records that meet the filters applied to my other datasource. Here we go:
Create a new datasource under your Employee model, leave it on the default 'Query Builder' type, adjust the query page size to your preference, but preferably to something that you know will return more than one page of records when querying the datasource. Uncheck the 'automatically load data' property unless you want to load all records when first going to your page where you set your filters. Do not enter anything in the query builder.
For the calculated datasource that you called Employee_RecordCount add your parameters, FirstName_equals, LastName_equals, Email_contains, StartDate_greaterequals, Age_lessequals, and Departments_equals, if you have not already. In this calculated model you should have a field called RecordCount. In the query script section of this datasource you should put your function as return getEmployeeRecords_(query).
In your server script section where your getEmployeeRecords function is the code should be as follows:
function getEmployeeRecords_(query) {
var params = query.parameters;
var ds = app.models.Employee.newQuery();
if (params.FirstName_equals !== null ) {
ds.filters.FirstName._equals = params.FirstName_equals;
}
if (params.LastName_equals !== null ) {
ds.filters.LastName._equals = params.LastName_equals;
}
if (params.Email_contains !== null) {
ds.filters.Email._contains = params.Email_contains;
}
if (params.StartDate_greaterequals !== null) {
ds.filters.StartDate._greaterThanOrEquals = params.StartDate_greaterequals;
}
if (params.Age_lessequals !== null) {
ds.filters.Age._lessThanOrEquals = parseInt(params.Age_lessequals, 10);
}
if (params.Department_equals !== null) {
ds.filters.Department.Department._equals = params.Department_equals;
}
var records = ds.run();
// update calculated model with record count
var calculatedModelRecord = app.models.Employee_RecordCount.newRecord();
calculatedModelRecord.RecordCount = records.length;
return [calculatedModelRecord];
}
Now go to your search page, create a new panel or form set it to the same new datasource that you created. Make sure you have all your appropriate fields and change the binding of these fields to:
#datasource.query.filters.firstName._equals
#datasource.query.filters.lastName._equals
#datasource.query.filters.email._contains
#datasource.query.filters.StartDate._greaterThanOrEquals
#datasource.query.filters.Age._lessThanOrEquals
#datasource.query.fitlers.Department.Department._equals
The button that initiates your search should have the following code:
var ds = widget.datasource;
ds.load(function() {
app.showPage(app.pages.YourSearchResultPage);
}
var calculatedDs = app.datasources.Employee_RecordCount;
var props = calculatedDs.properties;
props.FirstName_equals = ds.query.filters.firstName._equals;
props.LastName_equals = ds.query.filters.lastName._equals;
props.Email_contains = ds.query.filters.email._contains;
props.StartDate_greaterequals = ds.query.filters.StartDate._greaterThanOrEquals;
props.Age_lessequals = ds.query.filters.Age._lessThanOrEquals;
props.Department_equals = ds.query.filters.Department.Department._equals;
calculatedDs.load();
Now go to your search result page and make sure the you have the following elements:
A panel that the datasource is set to Employee_RecordCount. Inside
this panel create a label and set the binding to
#datasource.item.RecordCount.
A table that has the datasource set
to the same datasource as created in the first step. Make sure your
table has 'pagination' turned on.
That should be all, and this works in my application. It is a pain to set up, but I'm afraid it is the only workaround to have a total count of records. I should note that I have never had any paging issues either.

Complex LINQ Queries (Multiple Joins)

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.

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.

Linq to Entities: can't get collection query to work

I'm struggling to get a collection of records using L2E. Here's the model view:
http://pascalc.nougen.com/stuffs/aspnet_linq_model2.png
I have a user identifier, which is associated to 1 or many UserGroup which themselves are linked to TestCase. I would like to get all TestCases of all groups the user id X is associated to.
I also notice that I don't get all Project for users that are associated to 2 (or more).
Here's how I do so far:
QASModel.QASEntities qasEntities = new QASModel.QASEntities();
QASModel.User authenticatedUserEntity = (from u in qasEntities.Users
where u.ID.Equals(authenticatedUserId)
select u).FirstOrDefault();
// Get the authenticated user usergroups
var usergroup = authenticatedUserEntity.UserGroups.FirstOrDefault();
// Get all testcases of all user group the authenticated user is associated to
var allTestcases = usergroup.TestCases;
// Get the authenticated user projects based on it's usergroup(s)
var authenticatedUserProjects = usergroup.Projects;
authenticatedUserProjects give back only 1 project, where the user is linked to 2 projects.
And allTestcases gives back no result, although there are about 8 entries in TestCases associated to a project associated to one of the same UserGroup the user belongs to.
Thanks
I think your problem is in this line:
var usergroup = authenticatedUserEntity.UserGroups.FirstOrDefault();
Shouldn't your code get all UserGroups of that User? The above line will return only 1 UserGroup, this is, if the user belongs to more than 1 UserGroup the 2nd one won't be returned.
To correct this:
var userTestCases = new List<TestCase>();
var userProjects = new List<Project>();
foreach(UserGroup ug in authenticatedUserEntity.UserGroups)
{
userTestCases = userTestCases.Concat(ug.TestCases);
// Get the authenticated user projects based on it's usergroup(s)
userProjects = userProjects.Concat(ug.Projects);
...
}
var usergroup = authenticatedUserEntity.UserGroups.FirstOrDefault();
probably is wrong, since you want all usergroups the user is associated with.
In any case you can easily revert the query to work like this
var testcases = from tc in new QASModel.QASEntities().TestCases
where tc.UserGroup.UserId == USERID
select tc
This way you won't have to execute multiple queries to get all test cases, each FirstOrDefault or ToList or ForEach will actually execute the query.

Resources