Linq to SQL MVC issue with FK - asp.net-mvc

right having a bit of a hard mental blog with some Linq to SQL and MVC.
Getting the basic MVC and L2SQL going ok.
FK relationships. -> when using MVC and we have a fk relationship in the model,
and the view is based on a strongly typed object - how do you get the data from the related table?
So for example
User (Table)
UserId
UserName
Call (Table)
CallId
UserId
CountryId
Country(Table)
CountryID
CountryName
SO I want to get only the calls for a user with a specific country?
The view - based on Call Object as this is the "Details" view -
how do i get a UserName and CountryName and still maintain a view based on Call?
It would seem that I still have to create an Object CallForUserByCountry - but this gets messy
on save as the CallForUserByCountry object also needs to implement how to create Call User and Country.
the linq query
var calls = from c in db.Call
where c.CountryID == id
select new CallForUserByCountry or new something// this is bit that suggests a new object.
Hopefully I missing something ...

If the Call data class has associations to User and Call data classes you can access Call's User and Country properties directly in your View. Also you can load data from related User and Country tables immediately (instead of lazy loading by default):
In Controller:
DataLoadOptions options = new DataLoadOptions();
options.LoadWith<Call>(x => x.User);
options.LoadWith<Call>(x => x.Country);
db.LoadOptions = options;
var calls = from c in db.Call
where c.Country.CountryName == countryName && c.User.UserName == userName
select c;
In View:
<%= Model.User.UserName %>
<%= Model.Country.CountryName %>

You could use the TempData bag and save the Username and CountryName there.
in the controller:
TempData["CountryName"] = countryName;

If I'm understanding this correctly you are trying to get calls from a specific user with a specific country. If that's the case, then as long as you have the relationships mapped in the Linq2SQL designer, then you should be able to access the user and country from the call as properties. So it would be something like:
var userName = call.User.UserName;
As I said, this is contingent on the relationships being mapped in the designer, otherwise Linq2SQL will have no indication that the two tables are related.
You could also have a separate query to just get the calls you need based on User and Country:
var calls = from c in db.Call
where c.User.UserID = userID
&& c.Country.CountryID == countryID
select c;

Your question can be taken two ways.
You want to display a list of calls using the current Call Details View. - This would need a new view. Unless the details view is a ViewUserControl. Then you could use PartialRender.
You want to add extra data to the current Details View - Add the extra data to the ViewData.
For number 2 you could do the following.
i prefer using joins for this, and I like working with objects detached from my DataContext. So normally i don't have the extra IQueryable in my objects.
I would still use the CallForUserByCountry object. Makes things verbose.
var calls = from call in db.Calls
join country in db.Countries on call.CountryId equals country.CountryID
join user in db.Users on call.UserId equals user.UserId
where user.UserName == userName && country.CountryName == countryName
select new CallForUserByCountry
{
UserName = user.UserName,
CountryName = country.CountryName,
Call = call
};
View["CallsForUserByCountry"] = calls.ToList();
In the view.
<% foreach(var callForUserByCountry in (IList<CallForUserByCountry>)ViewData["CallsForUserByCountry"]) { %>
.. Do stuff here .. I like using PartialRendering
<% Html.PartialRender("CallForUserByCountryDetail", callForUserByCountry); %>
<%}

Related

MVC accessing linked table value using entity framework

I am new to entity framework and I am trying to get my head around it. I am used to writing stored procedures which have all the data I need on a example by example basis.
I am under the impression that I can get all values from a particular table including the foreign key values direct using entity framework without having to write a select query which joins the data.
I have the following in my controller
public ActionResult Patient()
{
using (var context = new WaysToWellnessDB())
{
var patients = context.Patients.ToList();
return View(patients);
}
}
In my view I have the following
#foreach (var item in Model)
{
<p>
#item.FirstName #item.Surname #item.Gender.GenderDesc
</p>
}
I have two tables, Patient and Gender, GenderId is a foreign key which I am trying to get the GenderDesc from that table.
I am getting the following message
The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.
Can someone explain why I cannot access GenderDesc. It does work if I remove the using() around my context, but I don't really want to leave that open, is there a way to get this to work still having the using around?
Thanks in advance.
Correct, you have disposed of the context as it is within a using statement, so anything you try to access from then on will not be able to be lazy loaded. The disadvantage with lazy loading is that it will perform a query for the gender for every patient you are iterating over, which is handy, but bad! I would load the related table at query time using Include.
You'll need a new import:
using System.Data.Entity;
And then include the related table:
var patients = context.Patients.Include(p => p.Gender).ToList();
That will result in a query which will join to your "Gender" table and you should be able to output item.Gender.GenderDesc in your view.

MVC4 Linq Database Call

Working on my first MVC app. I am using the simple membership database that comes with MVC4 to manage users and roles. My understanding is that I am having to do three steps for the Find() call below to work: get the simple membership GUID of the person logged in, use the simple membership GUID to get the ID in my Couriers database, then use that ID as the missing parameter in the Find() call below to return the model / record to edit in the view? How / what do I use as the parameter to the .Find() call? Am I on the right track, or making this a lot more complicated?
ps - I am saving the membership GUID in the Couriers database in a separate column from the Courier ID primary key column when the Courier record is created. Thank you.
public ActionResult EditCourier()
{
System.Web.Security.MembershipUser user = Membership.GetUser();
var providerUserKey = user.ProviderUserKey;
Guid userId = (Guid)providerUserKey;
String userIDstring = userId.ToString();
var model =
from c in db.Couriers
where c.CourierMembershipID == userIDstring
select c.ID;
Courier courier = db.Couriers.Find();
if (courier == null)
{
return HttpNotFound();
}
return View(courier);
}
MSDN documentation says:
Uses the primary key value to attempt to find an entity tracked by the
context. If the entity is not in the context then a query will be
executed and evaluated against the data in the data source, and null
is returned if the entity is not found in the context or in the data
source.
So if you have userId as a primary key in Couriers table then you can use .Find() like this:
Courier courier = db.Couriers.Find(userId);
Otherwise you should use standard LINQ query and then call .FirstOrDefault() or SingleOrDefault() method:
Courier courier = db.Couriers.FirstOrDefault(c=>c.CourierMembershipID == userIDstring);
EDIT:
I suppose you getting this error from next query:
var model =
from c in db.Couriers
where c.CourierMembershipID == userIDstring
select c.ID;
The reason is that you getting from this query IEnumerable<Courier> model.
For making this query to get single Courier object try to call .FirstOrDefault() at the end:
var model = (from c in db.Couriers
where c.CourierMembershipID == userIDstring
select c.ID).FirstOrDefault();

ASP.NET MVC Entity Framework Relationship binding

I'm using Entity Framework 5.0 for my MVC4 project. There's a problem with it. When i give a db model to any view, controller send model with no relationship
example;
I have User class and with relation departments
when i use it in controller
using(context)
{
var user = context.Find(id);
string department = user.Department.Name;
}
its working when call in context. but when i do that
using(context)
{
var user = context.Find(id);
return View(user);
}
and call in view like
Model.Department.Name
i got error.
Here is my answer but its not good
using(context)
{
var user = context.Find(id);
string department = user.Department.Name;
return View(user);
}
when i try to user Model.Department.Name in view i got no error i must do that for every relation when i use class as model. there is have better solution for this problem ? i want use all relationship in View without call these in controller.
I hope you can understand me, sorry my english.
On your DbContext you could use the .Include method to eagerly load the relations you need:
context.Users.Include(u => u.Department).FirstOrDefault(u => u.Id == id);
or if you are using an older version of entity Framework the generic version of this method might not be available:
context.Users.Include("Department").FirstOrDefault(u => u.Id == id);
The reason for this is that you haven't "loaded" the Department in your original code. As your context is wrapped in a using statement it's being disposed of before the view is created and therefore your user object lacks the data you want.
In your second code example you have specifically called into the related Department object and therefore it now exists within the User object.
You need to eager load the Department in your original line using something like
context.User.Include(c => c.Department).Find(id);
Now your user object should have this available in the view.
What are u trying to accomplish? List a view for a user with one or many departments?

.NET web application - how to find logged in user's database records?

In my .NET CRUD web application I implemented MembershipProvider class.
Now I have function that lists records from database (this controller requires authenticated user). I need to filter out these records with respect to this logged-in user.
//
// GET: /Library/
public ViewResult Index(String orderBy = "")
{
var books = db.Books.Include(b => b.Category).Include(b => b.Writer).Include(b => b.User);
return View(books.ToList());
}
I need to know how to get logged in user's UserId and use it in Where condition (every tutorial I found talks about getting username but I need UserId). Thank you in advance.
Data I store in *.mdf data file.
I think that what you need is:
Membership.GetUser().ProviderUserKey
The type of this is object, but if you are using the out of the box membership, it should be a guid. This can then be used to filter your select accordingly.
Membership is part of the built in Membership Provider with a number of static methods.
Without knowing your DB structure/ORM, I can't exactly say, but it will be something like:
Guid userId = (Guid)Membership.GetUser().ProviderUserKey;
var books = db.Books.Where(b => b.UserId == userId);

drop down list in MVC

I am absolutely new to the MVC application.I want a dropdown list on my form I have done it this way
"<%= Html.DropDownList("Categories", (IEnumerable<SelectListItem>)ViewData["Categories"])%>"
I am sending the viewdata[Categories] from the controller class file.
this way
IList allCategories = _dropdownProvider.GetAllCategories();
ViewData["Categories"] = new SelectList(allCategories, "catid", "catname");
Now my requirement is that when the user selects a particular category from the dropdownlist its id should get inserted in the database,
The main problem is category id I want to insert the category id in the product table where the category Id is the foreign Key.
Please tell me how can I do this.
Normally you would do the following:-
On your view you would have...
Inherits="System.Web.Mvc.ViewPage<Product>" THIS IS A REFERENCE TO YOUR PRODUCT ENTITY
and in the page you can do this...
Category <%=Html.DropDownList("CatId") %>
you would also have the GET controller which defines the list
public ActionResult Add()
{
ViewData["CatId"] = new SelectList(allCategories, "catid", "catname");
then you can get the CatId from the product passed in to the Add method
e.g.
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Add(Product product)
{
int catId = product.CatId
HTH. You ought to buy a book on the subject as MVC takes away alot of the pain of binding from you.
when you try to post the view, you'll have a "Categories" key in your querystring. you could convert it to long or the type you use in your table and set it to the product instance that you want to.
if this is not so clear, please send your code for a better explanation.
If i Understand right your question, the only thing you have to do, is inspect the POST for the "Categories" Key, and it will contain the selected value of the DropDownList.
var selectValue = System.Convert.ToInt16(Request.Form["name"]);
Or if you use ModelBinder and define a model that bind that value directly, you just have to Update the Model with
bool x = TryUpdateModel(YourModelNameHere);
This will automatically inspect the current ControllerĀ“s Value Provider and bind that value to the corresponding property in your model.
I recoment you to use the parameter FormCollection in your controller, and put a breakpoint, you can see all the values send within the POST. All that values are accessible through Request.Form["KEY"].

Resources