MVC4 - Linq Lambda expression to query multiple association tables - c#

Am trying to create a cascading drop down and have been following this tutorial here
My database is more complex than the one in the tutorial and I need help with creating a lambda expression
Here are my database tables
The cascading drop down I want to create, will allow a user to select a
RiskType and then depending on the selection will display the associated GroupMembers for the selected RiskType.
Here is the code I have in my controller
public ActionResult AddNewRisk()
{
ViewBag.RiskTypeID = new SelectList(_DBContext.RiskTypes, "ID", "Description");
ViewBag.GroupMembers = new SelectList(new List<GroupMember>(), "ID", "Name");
return View();
}
public IList<GroupMember> GetGroupMember(int SelectedRiskTypeID)
{
return _DBContext
.RiskTypeHasGroups
}
public JsonResult GetJsonGroupMember(int ID)
{
var GroupMemberListT = this.GetGroupMember(Convert.ToInt32(ID));
var GroupMemberList = GroupMemberListT.Select(x => new SelectListItem()
{
Text = x.Name,
Value = x.ID.ToString()
});
return Json(GroupMemberList, JsonRequestBehavior.AllowGet);
}
It's in the method named GetGroupMember that am having trouble and don't know how to write the correct lambda expression in order to pull back only the group members which have a matching RiskGroup.ID followed by a matching RiskType.ID. If anyone could show me the correct way to do this, I'd really appreciate it.
Thanks in advance.

Once the model is simplified as I suggested, then your query becomes:
public IQueryable<GroupMember> GetGroupMember(int SelectedRiskTypeID)
{
return _DBContext.GroupMembers
.Where(g=>g.RiskGroups.Any(rg=>rg.ID=SelectedRiskTypeID));
}
If you decide to keep the IDs, then this would be your query:
public IQueryable<GroupMember> GetGroupMember(int SelectedRiskTypeID)
{
return _DBContext.GroupMembers
.Where(gm=>gm.RiskGroupHasGroupTypes
.Any(rghgt=>rghg‌​t.RiskGroup.ID==SelectedRiskGroupTypeID))
}

Related

MVC - Pulling a database field from the model and using it in the controller

I'm trying to implement a database field from the model and use it in the controller.
So for example.
In Employees.cs Model class, there is a field AccIsActive and I want to use it in the controller so I could do a conditional statement.
I want to do a conditional statement so only the list view can check if AccIsActive is true so I could show the data. I don't want to do this in the front end as it can be easily modified.
This is what I have so far in my List method.
public ActionResult List()
{
IList<Employee> employees;
EmpContext emp = new EmpContext();
employees = emp.Employees.ToList();
return View(employees);
}
I'm trying to do something like...
if (AccIsActive == true)
{
.....
}
Query the active results with linq
employees = emp.Employees.Where(e => e.AcclsActive).ToList();
return View(employees);

add nested group by query Linq to property model class ASP.NET

I have struggle with adding the grouped data table with linq query to model property.
Here's my model
public class Ports
{
public String city { get; set; }
}
and here's my controller
public ActionResult ShipSchedule()
{
DatabaseContext db = new DatabaseContext();
var Ports = new Ports();
Ports.city = from m in db.ports_data group m by new { m.city } into n select new { n.Key.city };
return View();
}
I've replaced the model part to List<> and replaced again to another, but this part
Ports.city = (from m in db.ports_data group m by new { m.city } into n select new { newcity = n.Key.city }).ToList();
is still tell me that part cannot convert type 'system.collections.generic.list<<anonymous type: string newcity>>' to 'system.collections.generic.list<string>'
Did anyone know the correct ways from this?
and one more thing, I want to display that part to my view in dropdown, if anyone have a better ways
here's my view
#model example.Models.Ports
#{
List<SelectListItem> listItems = new List<SelectListItem>();
foreach (var mod in Model.city)
{
listItems.Add(new SelectListItem
{
Text = mod.ToString(),
Value = mod.ToString()
});
}
}
#Html.DropDownListFor(model => model.selected, listItems, "-- Select item --")
the error is telling you exactly what is wrong, you have a string but are trying to assign a list to it (two very different objects), you can simply:
public class Ports
{
public List<String> cities { get; set; }
}
which will make that string be valid, but a better practice would be make "Ports" a list and use it as List<Port> and each port will contain "city" (and all the other port properties).
but in any case to get all ports from the database you probably can do:
var ports = db.ports_data.ToList();
that should give you a list with all the ports in your database (no need to create that New Ports() and populate it, if you need to group by city it should be as easy as:
var ports = db.ports_data.GroupBy(x=>x.city).ToList();
in the comment you mentioned that you are getting duplicates, for that you may need distinct, but if you don't need duplicates you shouldn't be adding duplicates to the database to start with, so we would be touching the wrong end here, but in any case I believe you need Distinct() if combined with a select you will get only cities, different ones if there is duplicates:
var portsCities = db.ports_data.Select(x=>x.city).Distinct().ToList();
that will result in a List<string> of cities, all different
as you can see Linq have many ways to get exactly the data you need, I would play around with it and experiment, best way to learn!
I would also try to use LINQ method (as the examples above) if you are starting, it is easier to manage (more object oriented) you can see some examples here

how to avoid recording redundant data with MVC

I have a class with two properties (name,family).
I have written code for insert into database without problems, but I don't know how to write the code to check if the data already exists?
I need sample for MVC 4 or higher.
Thanks in advance.
public ActionResult Create([Bind(Include="Name,Description")] ColorApplication colorapplication)
{
if (ModelState.IsValid)
{
db.ColorApplications.Add(colorapplication);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(colorapplication);
}
If you wanna use the DbSet, there are the Remove() or RemoveRange() options.
You can eighter remove one:
using (PersonContext db = new PersonContext())
{
Person person = db.Persons.Where(t => t.Name == "My Name").FirstOrDefault<Person>();
db.Persons.Remove(person);
db.SaveChanges();
}
Or give a list of entities that you want to remove:
using (PersonContext db = new PersonContext())
{
List<Person> persons = db.Persons.Where(t => t.Name == "My Name").ToList();
db.Persons.RemoveRange(persons);
db.SaveChanges();
}
You can also use raw SQL statements if you need something more specific:
DELETE FROM PERSON WHERE NAME = 'My Name'

Reusing projections in queries, the part after "select new"

In my ASP.NET MVC Application, I have many actions that return JSONs.
In these JSONs, some sub-structures are repeated.
For example
ajax: "/Bands/Members" is supposed to return the members of a band, which are all musicians
ajax: "/Musicians/All" is supposed to return all the musicians on the system
ajax: "/Musicians/Search" is supposed to return all the musicians that match something
etc...
Here I show (1):
public JsonResult Members(long musicBandId)
{
MusicBand b = db.MusicBands.SingleOrDefault(b => b.MusicBandId == musicBandId);
if (b == null)
return null;
return Json(new
{
error = false,
message = "",
persons = from m in b.Members select new
{
musicianId = p.MusicianId,
name = m.Name,
instrument = new
{
instrumentId = m.instrument.InstrumentId,
model = m.instrument.Model
}
}
}, JsonRequestBehavior.AllowGet);
}
And here I show (2):
public JsonResult All(int page, int pageSize)
{
var musicians = db.Musicians;
var pageOfMusicians = musicians.Skip((page-1) * pageSize).Take(pageSize);
return Json(new
{
error = false,
message = "",
musiciansCount = musicians.Count(),
page = page,
pageSize = pageSize
musicians = from m in pageOfMusicians select new
{
musicianId = m.MusicianId,
name = m.Name,
instrument = new
{
instrumentId = m.instrument.InstrumentId,
model = m.instrument.Model
}
}
}, JsonRequestBehavior.AllowGet);
}
This has several problems:
If I want to change the JSON format, I have to change it in every single action!
example: If I want to change "name" to "fullname", I have to change it in Members() and All()
Lot of "copy pasting": If I'm creating a new action that somewhere in the structure returns a musician, I need to copy and paste that piece of code that represents the musician
{
musicianId = p.MusicianId,
name = p.Name,
instrument = new
{
instrumentId = instrument.InstrumentId,
model = instrument.Model
}
}
Code is too large
What solution exists to this problem?
If you propose a framework, please show me how would the previous queries look with that framework
Notice I'm always using Linq-to-entities in my examples, and I would like to keep it like that because of performance issues. I know that with Linq-to-objects I could to something like:
from m in pageOfMusicians.ToList() select m.GetDTO()
Being GetDTO() some method that can be run with Linq-to-Objects.
But then, again, I want to stick to Linq-to-Entities
Alternative 1
If you don't worry about using dynamics mixed with regular typed C# code you could make a utility method like...
public static dynamic PrepareForMusiciansView(IQuerable<Musician> musicians)
{
return musicians.Select(m => new
{
musicianId = m.MusicianId,
name = m.Name,
instrument = new
{
instrumentId = m.instrument.InstrumentId,
model = m.instrument.Model
}
}
}
...and then...
return Json(new
{
error = false,
message = "",
musiciansCount = musicians.Count(),
page = page,
pageSize = pageSize
musicians = Util.PrepareForMusiciansView(pageOfMusicians)
}, JsonRequestBehavior.AllowGet);
The method name should clearly reflect its purpose in terms of your application. Maybe you want to focus more on the serialization function and use a name like PrepareForJson. Also, it should be consistent with your coding standards. I would avoid it if nowhere else dynamics is used.
Alternative 2
Use AutoMapper (available via NuGet).
With AutoMapper you'd typically have DTO classes for Musician and Instrument, having the properties you want to expose in the view. If these properties have the same names as those in the source classes, AutoMapper will match them by name convention.
Using AutoMapper always involves defining the mappings and executing mappings. Defining the mappings should be done once at application startup. It looks like...
Mapper.CreateMap<Musician, MusicianDto>();
Mapper.CreateMap<Instrument, InstrumentDto>();
There are different ways to execute the mappings, but when working with IQueryable the preferred way is
musicians = pageOfMusicians.Project().To<MusicianDto>()
This projects IQueryable<Musician> to IQueryable<MusicianDto>, including the nested Instrument (if the DTO has a property of that name).
These are two viable alternatives I can think of to reduce the awkward new {} statements to reusable one-liners. It really depends on your application and coding style which alternative you prefer.

Please help me to return a list from my method

I am trying to get information from a database, convert it to a list and return the CustomerList. This first bit of code works fine. The second example is where I’m trying to accomplish the same thing except the fields are coming from my database. What’s wrong with what I’m doing and how can I make this work? The second piece of code works elsewhere in my project but not here.
private SchoolIn.Models.CustomerList CreateCustomerList()
{
return new SchoolIn.Models.CustomerList()
{
new SchoolIn.Models.Customer { Id = 1, Name = "Patrick", Address = "Geuzenstraat 29", Place = "Amsterdam" },
new SchoolIn.Models.Customer{ Id = 2, Name = "Fred", Address = "Flink 9a", Place = "Rotterdam" },
new SchoolIn.Models.Customer { Id = 3, Name = "Sjonnie", Address = "Paternatenplaats 44", Place = "Enkhuizen" },
new SchoolIn.Models.Customer { Id = 4, Name = "Henk", Address = "Wakerdijk 74", Place = "Utrecht" },
new SchoolIn.Models.Customer { Id = 5, Name = "Klaas", Address = "Paternatenplaats 44", Place = "Plaantan" }
};
}
private SchoolIn.Models.CustomerList CreateCustomerList()
{
return new SchoolIn.Models.CustomerList()
{
SchoolInDB db = new SchoolIn.Models.SchoolInDB();
var courseprogresses = db.CourseProgresses.Include(c => c.Course).Include(c => c.Teacher);
return View(courseprogresses.ToList());
};
}
First things first the second code is invalid C#. So I suppose it doesn't event compile. You cannot use such expressions in an object initialization syntax. Please learn C# before getting into ASP.NET MVC.
The other problem is that your method is private and you are attempting to return View which is something that you do in a controller action. The view method returns an ActionResult whereas your method return type is SchoolIn.Models.CustomerList which once again is wrong.
So move this into some controller action where you would instantiate your database access context and then perform the query and return the model to the corresponding view for display:
public class HomeController: Controller
{
...
public ActionResult CreateCustomerList()
{
SchoolInDB db = new SchoolIn.Models.SchoolInDB();
var courseprogresses = db
.CourseProgresses
.Include(c => c.Course)
.Include(c => c.Teacher)
.ToList();
return View(courseprogresses);
}
}
and if you wanted to keep this into a separate method:
private List<SchoolIn.Models.CourseProgress> CreateCustomerList()
{
SchoolInDB db = new SchoolIn.Models.SchoolInDB();
return db
.CourseProgresses
.Include(c => c.Course)
.Include(c => c.Teacher)
.ToList();
}
In your first function you are returning actual list while in second function you are not returning list, instead you have returned the View with model as a list. So for it you need to return View Result viz. ActionResult.
Hope it helps

Categories

Resources