Pass multiple data items from controller to view - asp.net-mvc

I am using VS 2010, MVC, VS 2005
I create .dbml file as my model and map tables inside .dbml file
i join tables using LINQ to SQL. I want to display record of two tables i.e. tbl_class, tbl_subject
COde in my controller looks like this
public ActionResult SubjectByTeacher()
{
var DataContext = new SMSAPPDataContext();
var resultclass = (from t in DataContext.tbl_teachers
from e in DataContext.tbl_teacherenrollments
from b in DataContext.tbl_batches
from c in DataContext.tbl_classes
from s in DataContext.tbl_subjects
where
t.Teacher_ID == e.Teacher_ID
&&
e.Batch_ID == b.Batch_ID
&&
b.Class_ID == c.Class_ID
&&
e.Sub_ID == s.Sub_ID
&&
t.Teacher_Name == "ABC"
select c;
var resultsubject = from t in DataContext.tbl_teachers
from e in DataContext.tbl_teacherenrollments
from b in DataContext.tbl_batches
from c in DataContext.tbl_classes
from s in DataContext.tbl_subjects
where
t.Teacher_ID == e.Teacher_ID
&&
e.Batch_ID == b.Batch_ID
&&
b.Class_ID == c.Class_ID
&&
e.Sub_ID == s.Sub_ID
&&
t.Teacher_Name == "ABC"
select s;
return View();
}
Then i create a class in controller to map above two variables i.e. resultclass, resultsubject
public class MyViewModel
{
public MyViewModel(SMSAPPDataContext resultclass, SMSAPPDataContext resultsubject)
{
this.rc = resultclass;
this.rs = resultsubject;
}
public SMSAPPDataContext rc { get; private set; }
public SMSAPPDataContext rs { get; private set; }
}
This class will be used in creating view as model in strongly typed view.
But i cant figure it out, what to pass in return view ?????
It may be just like i.e. return view(new myviewmodel);
But this gives error, Should i use ToList() property any where in code ???
If any one can told me any other way to do this, please help
Regards

Assuming your view is strongly typed to use MyViewModel, e.g:
<%# Page Language="C#" Inherits="System.Web.Mvc.ViewPage<YourNameSpaceHere.MyViewModel>" %>
Then using something like
return View(new MyViewModel(resultclass, resultsubject));
In the controller should work. Although I don't think SMSAPPDataContext is the correct type that the LINQ query will be returning.

Related

List<class> does not contain a definition for 'property'

So I'm trying to make a simple MVC system that will search through a database of books by author and/or title. I have a model called Book.cs with title and author properties. In my controller I made an ActionResult as follows:
public ActionResult Search(string theAuthor, string theTitle)
{
if (theAuthor == null && theTitle == null)
{
ViewBag.title = "Search for a book by author and/or title";
}
else
{
ViewBag.title = "Results:";
}
List<Book> allBooks = db.Books.ToList();
List<Book> booksFound = new List<Book>();
foreach (Book theBook in allBooks)
{
if (theAuthor != null && theTitle != null)
{
if (theBook.author == theAuthor && theBook.title == theTitle) booksFound.Add(theBook);
}else if (theAuthor == null)
{
if (theBook.title == theTitle) booksFound.Add(theBook);
}else if (theBook == null)
{
if (theBook.author == theAuthor) booksFound.Add(theBook);
}
}
return View("Search", booksFound);
}
Now, this returns a List of books, so I assume that in my view I have to use List<Book> model, and so I did (#model List<Book>). But the problem is how am I going to send data to the action result? I tried using
#Html.TextBoxFor (x => x.author)
But that gives the
'List<Book>' does not contain a definition for 'author' and no extension method 'author' accepting a first argument of type 'List<Book>' could be found (are you missing a using directive or an assembly reference?)
error. Now that makes sense to me because I guess I can't access model class property if my model is a list. So am I doing something wrong or I should use another way to pass data?
Thanks
I didn't get your question when you said "But the problem is how am I going to send data to the action result?" but as much as I could comprehend from your question it seems you want to iterate the model which is a list of 'Book' objects inside MVC view. Controller has passed that list to your view as a model and then you want to create some UI elements based on the elements in the list. Here is how you can do it:
#for (int i = 0; i < Model.Count; i++)
{
#Html.TextBoxFor(x=> x[i].author)
}
To answer your other concern, there is absolutely no error in the way you have passed the model (which is a list) from controller to view but you were trying to access the author property on the list itself when it is available on the list elements. Hope this helps!

How to improve my Entity Framework , to join several database queries into single query

I have the following ActionFilter class, to implement my custom authorization system:-
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class CheckUserPermissionsAttribute : ActionFilterAttribute
{
Repository repository = new Repository();
public string Model { get; set; }
public string Action { get; set; }
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
string ADusername = filterContext.HttpContext.User.Identity.Name.Substring(filterContext.HttpContext.User.Identity.Name.IndexOf("\\") + 1);
if (!repository.can(ADusername,Model,Action))
{
filterContext.Result = new HttpUnauthorizedResult("You cannot access this page");
}
base.OnActionExecuting(filterContext);
}
}
The above class will call the following repository method:-
public bool can(string user, string Model, string Action)
{
bool result;
bool result2;
int size =tms.PermisionLevels.Where(a5 => a5.Name == Action).SingleOrDefault().PermisionSize;
var securityrole = tms.SecurityroleTypePermisions.Where(a => a.PermisionLevel.PermisionSize >= size && a.TechnologyType.Name == Model).Select(a => a.SecurityRole).Include(w=>w.Groups).Include(w2=>w2.SecurityRoleUsers).ToList();
foreach (var item in securityrole)
{
result = item.SecurityRoleUsers.Any(a => a.UserName.ToLower() == user.ToLower());
var no = item.Groups.Select(a=>a.TMSUserGroups.Where(a2=>a2.UserName.ToLower() == user.ToLower()));
result2 = no.Count() == 1;
if (result || result2) {
return true;
}}
return false;
}
But inside my repository method , I am doing the following:-
Query the database and include all the Groups & SecurityRoleUsers when executing the .tolist()
Then filter the returned records insdie the server, based on the foreach loop.
But this will cause the following drawbacks:-
If I have many Groups and SecurityRoleUsers, then I will be getting them all from the DB, and then filter the result on the server.
And since this code will be executed whenever an action method is called, as it Is a security attribute at the begging of the controller class. So this might not be very efficient.
So my question is whether I can join all the queries inside the repository method to be single query , and do all the work on the Database and just return true or false to the server ?
The associated tables looks as follow:-
Ideally remove this foreach.
Try riding with Linq to Sql.
You should be more comfortable because it resembles SQL.
This link has several examples.
http://code.msdn.microsoft.com/101-LINQ-Samples-3fb9811b
Att
Julio Spader
wessolucoes.com.br
Use linq.
Ideally you should only have one line of code after you got the size value. e.g.
int size =tms.PermisionLevels.Where(a5 => a5.Name == Action).SingleOrDefault().PermisionSize;
var result = //One line of code to determine user authenticity
return result;
I think you should design you database in the way that join queries are easy to do. So you don't have to perform more than one select.
Try code-first EF, which links tables very easily.
You need to take care with Lazy Loading. If not used correctly, it will make a query to the database each object segmentation, especially in your foreach. With that already has a good improvement.
Take a look at this article. I think it will help you too.
http://www.sql-server-performance.com/2012/entity-framework-performance-optimization/
Att
Julio Spader
wessolucoes.com.br

Linq casting Issue in EntityFramework

Hi,
I am new to Linq and entity framework. I am doing something like this
I have 3 viewmodel:
1.
public class FlowViewModel
{
..........................
public List<FlowLevelViewModel> Levels { get; set; }
}
public class FlowLevelViewModel
{
.........................
public List<BlockDetailsViewmodel> Blocks { get; set; }
}
public class BlockDetailsViewmodel
{
.......................
}
and from my controller I am calling the datalayer.
var model = new FlowViewModel();
model = dataOb.GetFlowForTheDocument(company, docType);
model = dataOb.GetFlowStageForTheDocument(model);
return model;
and in my datalayer
public FlowViewModel GetFlowStageForTheDocument(FlowViewModel model)
{
var flowlevelviewModel = (from p in dbContext.FlowStages
where p.FlowID == model.FlowId
select new FlowLevelViewModel()
{
.................
Blocks = GetBlockDetailsForTheDocument(p.StageID, .StageType)
}).ToList();
model.Levels = flowlevelviewModel;
return model;
}
public List<BlockDetailsViewmodel> GetBlockDetailsForTheDocument(int StageID, string stageType)
{
var blockDetails = new List<BlockDetailsViewmodel>();
......................................
return blockDetails;
}
While I am running the program I am getting this error:
**NotSupportedException Was unhandled by user Code**
LINQ to Entities does not recognize the method 'System.Collections.Generic.List`1[SEADViewModel.BlockDetailsViewmodel] GetBlockDetailsForTheDocument(Int32, System.String)' method, and this method cannot be translated into a store expression.
My project is in production stage so I have no time at all. Does anyone know what I am doing wrong?
This should solve your problem:
var data = (from p in dbContext.FlowStages
where p.FlowID == model.FlowId
select p).ToList();
var flowlevelviewModel = (from p in data
select new FlowLevelViewModel()
{
.................
Blocks = GetBlockDetailsForTheDocument(p.StageID, .StageType)
}).ToList();
Note that this will evaluate the query at the first ToList(). If you need to run the entire query at once, you need to build a simple LINQ expression, you can't use your method GetBlockDetailsForTheDocument inside the query. See #Tilak's answer for a link to supported build in methods.
You are using Linq to Entities.
It does not support all the functions. List of supported and non supported functions
You need to write custom model defined function GetBlockDetailsForTheDocument to use it in LINQ query.

ASP.NET MVC + EF 4.3.1 + DbContext - some null associations

I am using ASP.NET MVC 3 with EF 4.3.1, and the "EF 4.x DbContext Generator for C#" extension. I'm using the repository pattern.
The problem I'm having is that EF is not populating associations in some cases where I would expect it to. Is there something I need to do to trigger the population of all associations?
For example, I have an Assignment model that contains the properties "CompanyPartyId" and "EmployeePartyId". Both these properties have FKs to Parties.PartyId. That causes two associations to exist, Party (pointing to the Party specified by CompanyPartyId) and Party1 (pointing to the Party specified by EmployeePartyId).
For some reason, after saving a new Assignment, and retrieving it, the Party association is null. Both CompanyPartyId and EmployeePartyId properties are set to values which exist in Parties.PartyId. I have a similar issue with several other properties/associations; the properties are not null and contain valid values, but the association is null.
If it's relevant, Assignment uses a composite key; CompanyPartyId, EmployeePartyId, AssignmentTypeCode, and AssignmentStartDate.
The code in my controller looks like this (omitting validation and irrelevant logic):
[HttpPost]
[Authorize(Roles = "assignment_edit")]
public ActionResult Create(AssignmentViewModel assignment)
{
var newAssignment = assignment.NewAssignment;
partiesRepository.SaveAssignment(newAssignment);
var savedAssignment =
partiesRepository.Assignments.First(x => x.CompanyPartyId == newAssignment.CompanyPartyId &&
x.EmployeePartyId == newAssignment.EmployeePartyId &&
x.AssignmentTypeCode == newAssignment.AssignmentTypeCode &&
x.AssignmentStartDate == newAssignment.AssignmentStartDate);
var companyPartyId = savedAssignment.CompanyPartyId; // 1
var companyParty = savedAssignment.Party; // null
var employeePartyId = savedAssignment.EmployeePartyId; // 2
var employeeParty = savedAssignment.Party1; // not null
return View("Index");
}
The repository code is simple:
public IQueryable<Assignment> Assignments
{
get { return _context.Assignments; }
}
public void SaveAssignment(Assignment assignment)
{
var data = (from a in _context.Assignments
where a.CompanyPartyId == assignment.CompanyPartyId
&& a.EmployeePartyId == assignment.EmployeePartyId
&& a.AssignmentTypeCode == assignment.AssignmentTypeCode
&& a.AssignmentStartDate == assignment.AssignmentStartDate
select a);
if (!data.Any())
{
_context.Assignments.Add(assignment);
}
_context.SaveChanges();
}

how can i have my page inherit from a class instead of a table?

i need to access data from a table and from a view on a particular page, so i made a class that can access them both. looks like this `
namespace LoanManager.Models
{
public class Loan_vwFieldValues
{
public Loan loan { get; set; }
public VW_FIELD_VALUE vwFieldValues { get; set; }
}
}
at the top of my page i have this
<%# Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" AutoEventWireup="true" Inherits="System.Web.Mvc.ViewPage<IEnumerable<LoanManager.Models.Loan_vwFieldValues>>" %>
then i have this my controller after some other other code that works.
return View(_db.LOAN_VWFIELDVALESs.Where(predicate));
and my definition for that looks like this.
public System.Data.Linq.Table<Loan_vwFieldValues> LOAN_VWFIELDVALESs
{
get
{
return this.GetTable<Loan_vwFieldValues>();
}
}
this works fine for all the rest of my pages (they have different names of course), but they are not a class, they just reference one table or a view i have made, but this page needs to access a table and a view, but it complains when it gets to this last part of posted code(return statement) and says that Loan_vwFieldValues is not mapped as a table, which is true because it is NOT a table,
i also have this to fill the Loan_vwFieldValues
public ActionResult LoanProperties(int id)
{
Loan_vwFieldValues l = new Loan_vwFieldValues();
l.loan = (from a in _db.Loans where a.LOAN_ID == id select a).First();
l.vwFieldValues = (from v in _db.VW_FIELD_VALUEs where v.Loan_ID == id select v).First();
return View(l);
}
but how can i get this to work with my class?
thank you in advance.
You need to create a collection of Loan_vwFieldValues and return that. We don't have enough information to tell you how to construct those objects from your data access layer.
In other words...
return View(_db.LOAN_VWFIELDVALESs.Where(predicate).Select(
x => new Loan_vwFieldValues()
{
loan = yourCodeHere,
vwFieldValues = moreOfYourCodeHere
}));
thanks every one that helped, i found the solution by doing the following... i hope it can help others as well.
IQueryable<Loan> loanList = _db.Loans.Where(predicate);
List<Loan_vwFieldValues> loanVwList = new List<Loan_vwFieldValues>();
foreach (Loan loan in loanList)
{
Loan_vwFieldValues loanVw = new Loan_vwFieldValues();
loanVw.loan = loan;
loanVw.vwFieldValues = (from n in _db.VW_FIELD_VALUEs where n.Loan_ID == loan.LOAN_ID select n).First();
loanVwList.Add(loanVw);
}
return View(loanVwList);

Resources