Automapper and MvcPager3 working together - c#

I want to add Pagination to one of my views using MvcPager3. This would be simple, except that I'm already using AutoMapper to map my model to a simplied viewmodel.
List<Call> calls = (from p in db.Calls orderby p.ID descending select p).ToList();
var viewModel = new List<CallListItem>();
Mapper.Map(calls, viewModel);
return View(viewModel);
I thought it might be as simple as replacing this line
var viewModel = new List<CallListItem>();
with this
var viewModel = new PagedList<CallListItem>();
But PagedList has a constructor which takes a list of items. Since automapper is going to be doing this for me I thought I might be able to pass null, but it doesn't work.
Anybody have experience with using these two components in harmony?
Thanks
Edit:
Found an alternative to MvcPager called PagedList. It's much better because it has a StaticPagedList class which you can use for data which has already been paged.

You could paginate the view model after the mapping:
var calls = (from p in db.Calls orderby p.ID descending select p).ToList();
var viewModel = Mapper
.Map<IEnumerable<Call>, IEnumerable<CallListItem>>(calls)
.ToPagedList(currentPage, pageSize);
return View(viewModel);

Alternately, you can paginate first and map afterwards by using StaticPagedList.
This worked for me:
var calls = (from p in db.Calls orderby p.ID descending select p).ToPagedList();
var viewModel = Mapper.Map<IEnumerable<CallListItem>>(calls);
return new StaticPagedList<CallListItem>(viewModel, calls);
I did this because I did not want to list all the objects in order to page later.
Based on this nice post.

Related

Entity Framework split string

Outside of the main model I am building this list which I am them adding to a the main model that the method is returning. I wanted to know if I can do all this work inside building the main model?
Before building the main model
string Territorystring = (from p in db.Projects
join pm in db.ProjectMaterialUses on p.ProjectId equals pm.ProjectId
where projectId == p.ProjectId
select pm.Territory).FirstOrDefault();
List<string> guidStrings = TerritoryOfDistributionList.Split(',').ToList();
List<Guid> guids = guidStrings.Select(Guid.Parse).ToList();
List<Model.Country> = (from co in db.vwCountryItemDictionaries
where guids.Contains(co.CountryGUID)
select new Model.Country
{
Name = co.Name
}).ToList();
Main model
select new Project
{
TerritoryOfDistributionList = TerritoryOfDistributionList,
.....
}
When your list is used client-side, I'm assuming it will be in the form of an array. If that's true, then you could always switch your csv over to a json array (assuming your territory links aren't expecting to change):
https://learn.microsoft.com/en-us/sql/relational-databases/json/json-data-sql-server?view=sql-server-ver15
If the territory links are expected to change, you could always do version-chaining/updates via bulk sql statements.
Alternatively, you could set up a view, and read against that instead.

How to combine two queries and get one List in mvc c#

How can I combine these two lists in one List?
public IActionResult Open(int? id)
{
var questions = (from q in _context.Questions where q.CategoryId == id select q).ToList();
var answers = (from s in _context.Answers
join b in questions
on s.QId equals b.ID
group s by b.ID into g
select g.Count()).ToList();
if (questions == null)
{
return NotFound();
}
return View(questions);
}
The problem you are facing is a common one. As already mentioned by #Arripe here, you can create a ViewModel that is a composite class with the properties from each class that you want to use in your presentation layer. With a simple search for "create viewmodel asp.net mvc" or similar, you can find a guide to creating a ViewModel. Yours might be called "QuestionAnswerViewModel".
Constructing the actual ViewModel can be clunky (loop through each collection, mapping properties as you go), or you can be more creative with it.
For example, you could try joining the two query results into a combined result list, with the results being of type .
See #JonSkeet example here: how do I join two lists using linq or lambda expressions
I think what you're trying to get is Questions with number of Answers you have for them, right? If that's the case, then I think this should be the simplest solution. Of course you'll need to update the View to work with the new object.
var questionsWithAnswerCount = _context.Questions.Where(q => q.CategoryId == id)
.GroupJoin(_context.Answers, // list you join with
q => q.ID, // "main" list key
a => a.QId, // joined list key
(q, a) => new { Question = q, AnswerCount = a.Count() } // what to do with result - create new object that has Questions & Number of answers
)
.ToList();
if (questionsWithAnswerCount.Any()) // No need to check for null since you're calling .ToList() which will return an empty list, even when no elements were found, instead call .Any() to check if the list is empty or not
{
return View(questionsWithAnswerCount);
}
return NotFound();
Use a ViewModel to store two list and pass it to the View

I want to retrieve data from multiple tables to service payer into my project

want to retrieve data from multiple tables to service layer as I have to write database logic into service layer into my project
'KeysPlus.Service.Models.QuoteModel' to 'System.Collections.Generic.IEnumerable'.
An explicit conversion exists (are you missing a cast?)
Any help is highly appreciated!
public static IEnumerable<QuoteModel> GetJobQuotes(Login login, QuoteModel model)
{
using (var db = new KeysEntities())
{
var quotes = db.JobQuote.Where( x=> x.ProviderId == login.Id);
model = (from q in db.JobQuote
join j in db.Job on q.JobId equals j.Id
join p in db.Property on j.PropertyId equals p.Id
join a in db.Address on p.AddressId equals a.AddressId
select new QuoteModel
{
JobDescription=j.JobDescription,
QuoteAmount=q.Amount,
PropertyAddress= a.City
}).ToList();
return model;
}
}
You have a parameter in your method named model which is a single QuoteModel and you trying to set its value to a collection of QuoteModel. Remove that parameter (you not using it) and change the code to
using (var db = new KeysEntities())
{
var quotes = db.JobQuote.Where( x=> x.ProviderId == login.Id);
IEnumerable<QuoteModel> model = (from q in db.JobQuote
....
}
You have a model instance:
QuoteModel model
And you're trying to set it to a collection of model instances:
model = (from q in db.JobQuote
...
).ToList();
An apple is not a basket of apples. So you need to do one of two things, depending on what you actually want this method to do...
Return one model?
If you're looking for a specific instance from that list, then you need to add a clause to the query to return just that instance. Methods like .First() or .FirstOrDefault() can do that (or the .Single() equivalents). For example, if you want an instance which matches a specific value, it might look something like this:
model = (from q in db.JobQuote
...
).First(j => j.ID == someIdentifier);
Where of course someIdentifier is some value you have which you can use in the query. Perhaps model.ID or something like that? Depends on how you want to query your data, which we don't know here. But the point is that you need to return one model, not many models.
Additionally, you'd need to change the method's return type to QuoteModel, since you'd just be returning that one model instance.
Return many models?
Conversely, if you do want to return multiple models, then you can't put them in a variable which holds only one model. Just return the value directly:
return (from q in db.JobQuote
...
).ToList();
(Of course, then you're not even using the model variable, so why require it?)

Linq Conversion From ICollection<T> to List<T>

I am using Code First Entity Framework.
I am using the following simple classes:
public class Users
{
public ICollection<Projects> Projects{get;set;}
}
public class Projects
{
public ICollection<Users> Users{get;set;}
}
I am using linq for data retrieval. When performing the following query: (Note that lstProjects is a List<Project>)
var lstUsers = (from users in lstProjects
where users.ProjectId == pId
select users.Users).ToList();
I have a List<Users> object and want to populate this List with items. Like,
var lstUsersToDisplay = new List<Users>();
lstUsersToDisplay = (List<Users>)lstUsers; //This can't be cast.
What's the approach to convert ICollection<T> to List<T>?
Secondly, I have List<Users> and want to convert it into ICollection<Users> how achieve this?
Edited:
Scenario, more clearly is that
All Projects are loaded in lstProjects and we need to select the Users which were mapped to a specific project. These Users are also are contained inside Projects as collection. Every Project has its Users collection like if I decomposed the lstProjects it would be like:
lstProjects --> [0]-->//other Properties
ICollection[Users]-->[0]//Contains User class Properties
[1]....
[1] ... same procedure
Hope it clears the scenario
If your query is genuinely this:
var lstUsers = (from users in lstProjects
where users.ProjectId == pId
select users.Users).ToList();
then that's equivalent to:
List<ICollection<Users>> lstUsers = (from users in lstProjects
where users.ProjectId == pId
select users.Users).ToList();
If you're trying to get the list of uses from a single project, I'd write that as:
var lstUsers = lstProjects.Single(project => project.ProjectId == pId)
.Users
.ToList();
If there could be multiple projects with the same ProjectId, you want to flatten the users. For example:
var lstUsers = lstProjects.Where(project => project.ProjectId == pId)
.SelectMany(project => project.Users)
.ToList();
Or in query expression syntax:
var lstUsers = (from project in lstProjects
where project.ProjectId == pId
from user in project.Users
select user).ToList();
Note the fact that my range variable is called project, because it refers to a project, not a user. Naming is important - pay attention to it. I would also rename the Projects and Users types to just Project and User, assuming each is really only meant to represent a single entity.
lstUsers isn't a List<User>. It's a List<ICollection<User>>. You map each project to a sequence of users, not to a single user. To flatten a collection of collections into just a collection of the inner items you would use SelectMany, or, in query syntax, you'd write out your query like so:
var lstUsers = (from project in lstProjects
where project.ProjectId == pId
from user in project.Users
select user).ToList();
Now you have a List<User> for lstUsers. You can assign that as is to a List<User> or an ICollection<User>
using System.Linq; //include extension method OfType<> for ICollection
...
List<Projects> userList = lstUsers.OfType<Projects>().ToList();

Databinding to LINQ query result in Silverlight

I am retrieving simple LINQ query, but I am joining with two table and binding data with ListBox.
I am not able to properly show the item into the ListBox.
once I remove new item and select only keyword using it will work properly, but I want to join two table with select new key word it wil not allow to bind data with ListBox.
my code is like.
This will not allow to bind with ListBox.
var newPeople = (from p in clsGeneral.db.Table<SmartFXAttribes>()
join q in clsGeneral.db.Table<CategoryAttribes>() on p.catId equals q.ID
where p.catId == ((SmartFX.CategoryAttribes)((ComboBox)cmbPrintSize).SelectedValue).ID
select new
{
p.ID,
p.ImageHeight,
p.Imageoutline,
p.ImageUnit,
p.ImageWidth,
p.NoofPic,
p.TextboxCaption,
p.CanvasPixelHeight,
p.CanvasPixelWidth,
p.CanvasUnit,
p.catId,
q.FileName
}).ToList();
lstThumbnail.ItemsSource = newPeople;
This code will work fine.
var newPeople =
(from p in clsGeneral.db.Table<SmartFXAttribes>()
join q in clsGeneral.db.Table<CategoryAttribes>() on p.catId equals q.ID
where p.catId == ((SmartFX.CategoryAttribes)((ComboBox)cmbPrintSize).SelectedValue).ID
select p).ToList();
lstThumbnail.ItemsSource = newPeople;
Thanks!
The problem is that the first query creates an anonymous-typed object, but Silverlight cannot do data binding against an anonymous-typed object (anonymous types are internal and Silverlight's reflection capabilities do not allow accessing internal types from other assemblies). Your second query returns objects of a named type so it works just fine.
The best solution to this is to declare a public type containing public properties for everything you want to return from your first query and return an instance of that instead.
You can work around it with this hack, though.

Categories