MVC5: Foreign Key and data access - asp.net-mvc

I am looking for selecting a list from my table based on another table. I need to retrieve system names that are part of a particular system family. i have already added foreign keys. I created a ViewModel containing both these classes but it throws a null pointer exception. I am new to MVC and I am not sure where I am wrong.
Model Class : Systems
public class Systems
{
public int SystemsID { get; set; }
public string SystemName { get; set; }
public DateTime CreatedOn { get; set;}
public string CreatedBy { get; set; }
public int SystemFamilyID { get; set; }
public virtual SystemFamily SystemFamily { get; set; }
}
Class SystemFamily
public class SystemFamily
{
public int SystemFamilyID { get; set;}
public int SystemsID {get;set;}
public string FamilyName { get; set; }
public DateTime DateCreated { get; set; }
public string CreatedBy { get; set; }
public virtual ICollection<Systems> Systems { get; set; }
}
ViewSystem is a method in my SystemFamilyController.
public ActionResult ViewSystem(int? id)
{
var viewmodel = new Sys_SysFam();
ViewBag.SystemFamilyID = id.Value;
//if (id != null)
//{
// ViewBag.SystemFamilyID = id.Value;
// viewmodel.Systems = viewmodel.SystemFamily.Where(
// i => i.SystemFamilyID == id.Value).Single().Systems;
//}
return View(viewmodel);
}
the view :
#model SystemFam_System.ViewModel.Sys_SysFam
#{
ViewBag.Title = "ViewSystem";
}
<h2>ViewSystem</h2>
<p>#ViewBag.SystemFamilyID</p>
<table>
#foreach (var item in Model.Systems)
{
string selectedRow = "";
if (item.SystemFamilyID == ViewBag.SystemFamilyID)
{
//{
// selectedRow = "success";
//}
<tr class="#selectedRow">
<td>
#item.SystemName
</td>
<td>
#item.SystemsID
</td>
<td>
#item.SystemFamily
</td>
</tr>
}
}
</table>
I get null pointer Exception. I want to view the system that belongs to a particular family in view system.
Thanks in advance!!
Vini
Edit :
public class Sys_SysFam
{
public IEnumerable<Systems> Systems { get; set; }
public SystemFamily SystemFamily { get; set; }
}

Ok i have checked Sys_SysFam class too. As per your current code it will always throw null reference exception becasue in your controller code you are using:
public ActionResult ViewSystem(int? id)
{
var viewmodel = new Sys_SysFam();
ViewBag.SystemFamilyID = id.Value;
//if (id != null)
//{
// ViewBag.SystemFamilyID = id.Value;
// viewmodel.Systems = viewmodel.SystemFamily.Where(
// i => i.SystemFamilyID == id.Value).Single().Systems;
//}
return View(viewmodel);
}
here you are creating an object of Sys_SysFam as viewmodel and as your if part is commented so you are returning same viewmodel in which viewmodel.Systems will always be null. Here i did not see any request to database for getting the data from db but i think your data in viewmodel will come from database and if i uncomment your if condition then too you are not sending any request to database you are using same viewmodel object created above.
viewmodel.Systems = viewmodel.SystemFamily.Where(
i => i.SystemFamilyID == id.Value).Single().Systems;
in right side you are using viewmodel.SystemFamily with where condition but as viewmodel.SystemFamily is null it will always throw exception. Your solution should be something like this:
public ActionResult ViewSystem(int? id)
{
DataContext context = new DataContext();
var viewmodel = new Sys_SysFam();
ViewBag.SystemFamilyID = id.Value;
if (id != null)
{
ViewBag.SystemFamilyID = id.Value;
var sysFamily = context.SystemFamily.Include(x => x.Systems).FirstOrDefault(x => x.SystemFamilyID == id.Value);
if (sysFamily != null)
{
viewmodel.Systems = sysFamily.Systems;
}
}
return View(viewmodel);
}
here first i am creating object of DataContext which is my main context to access the database using entity framework. so first i will get the system family based on passed id from database and if system family is not null then i will set the data of systems in viewmodel. Include method will bring data for Systems based on system family from database.
Also improve your Sys_SysFam class to initialize systems so that it will not throw exception in your view when there is no data in viewmodel.Systems like this:
public class Sys_SysFam
{
public Sys_SysFam()
{
this.Systems = new List<Systems>();
}
public SystemFamily SystemFamily { get; set; }
public IEnumerable<Systems> Systems { get; set; }
}
Hope this will help you.

Remove SystemsID property from SystemFamily class because it is not used for ICollection virtual property. so your SystemFamily class should be like this:
public class SystemFamily
{
public int SystemFamilyID { get; set;}
public string FamilyName { get; set; }
public DateTime DateCreated { get; set; }
public string CreatedBy { get; set; }
public virtual ICollection<Systems> Systems { get; set; }
}

A friend of mine could find me a way. But it doesnt use any ViewModel. I would like to know how it need to be done with ViewModel as well..
public ActionResult ViewSystem(int? id)
{
var model = from item in db.Systems
orderby item.SystemsID
where item.SystemFamilyID == id
select item;
return View(model);
}

Related

repeater foreach in asp.net mvc

I'm building a website in ASP.Net, using MVC, and need to list a set of results
but i get error in the code
model:
public class Customers
{
public int Id { get; set; }
public string Name { get; set; }
public List<Customers> Itemlst { get; set; }
}
controller:
public ActionResult List()
{
Customers itemobj = new Customers();
return View(itemobj);
}
view:
#foreach(var item in Model.Itemlst)
{
<tr>
<td>Items ID:</td>
<td>#item.ID</td>
<td>Items Name:</td>
<td>#item.Name</td>
</tr>
}
</table>
From the NullReferenceException that you are receiving we can see that the issue is because of the Itemlst not being initialised. One of the ways to solve this is just to make sure that there is a valid list when you create the object:
public class Customers
{
public Customers()
{
Itemlst = new List<Customers>();
}
public int Id { get; set; }
public string Name { get; set; }
public List<Customers> Itemlst { get; set; }
}
So you can add values to the list in your action if need:
public ActionResult List()
{
Customers itemobj = new Customers();
var example = new Customers ();
example.Id = 1;
example.Name = "Example";
itemobj.Add();
return View(itemobj);
}
I don't know if you are just using this as an example for your question, but I can't help but notice that there is something weird. You could use something different like:
public class ViewModel // Name to what makes sense to you
{
// Some other properties...
public List<Customer> Customers { get; set; }
}
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
}
Or you could just use List<Customer> as your model in the view directly (yes, your model can be a object which is simply a list of objects).
When you pass the Customers list to the view, this list itself is the model.
Change Model.Itemlst —> Model inside the foreach loop.
This will iterate the list of customers.

Get id after add new item by Entity Framework

I need help with Entity Framework.
Controller:
public ActionResult Create([Bind(Prefix = "visit")] visit visit, [Bind(Prefix = "drugsEdition")] IEnumerable<drugsEdition> drugsEdition, [Bind(Prefix = "accessoryEdition")] IEnumerable<accessoryEdition> accessoryEdition, [Bind(Prefix = "servicesEdition")] IEnumerable<servicesEdition> servicesEdition)
{
Models.VisitDetails visitDetails = new Models.VisitDetails();
visitDetails.visit = visit;
if (ModelState.IsValid)
{
db.visit.Add(visit);
if (drugsEdition != null)
{
foreach (var item in drugsEdition)
{
item.idVisit = visit.id;
db.drugsEdition.Add(item);
}
}
if (accessoryEdition != null)
{
foreach (var item in accessoryEdition)
{
item.idVisit = visit.id;
db.accessoryEdition.Add(item);
}
}
if (servicesEdition != null)
{
foreach (var item in servicesEdition)
{
item.idVisit = visit.id;
db.servicesEdition.Add(item);
}
}
db.SaveChanges();
return RedirectToAction("Details", new { id = visit.id });
}
return View(visitDetails);
}
Model:
[Table("servicesEdition")]
public partial class servicesEdition
{
public int id { get; set; }
public int idService { get; set; }
public int idVisit { get; set; }
public double priceSell { get; set; }
[ForeignKey("idService")]
public virtual services services { get; set; }
}
In this code, I added a new visit to the database, and I want get the visit's id after the code line db.visit.Add (visit). When I add new drugsEdition and new accessoryEdition, this code is correct and added good idVisit, but when I addedservicesEdition idVisit = 0. Why 'servicesEdition' doesn't get good idVisit ?
If you add a virtual navigational property of type Visit, EF will get the corresponding visit id and fill that in when it saves a servicesEdition object on your SaveChanges method call.
I would also renaming the foreign key property to VisitId so that the referential integrity works by convention (naming convention) and you do not need to explicitly use the ForeignKey attribute. I would also recommend you to use PascalCasing when writing C# classes( not necessarily needed for your code to work)
public partial class ServicesEdition
{
public int id { get; set; }
public int idService { get; set; }
public int VisitId { get; set; }
public virtual Visit Visit { get; set; }
public double priceSell { get; set; }
[ForeignKey("idService")]
public virtual services services { get; set; }
}
If you do not want to alter the ServicesEdition entity definition like i described above, another option is to call the SaveChanges() method after you add the Visit entity and then you can access the Id property of that.
db.visit.Add(visit);
db.SaveChanges();
var visitId = db.Id;
//Now you can use visitId to save other entities
The issue is db.visit.Add(visit); does not generate id until hit db.SaveChanges();
You could add db.SaveChanges(); after db.visit.Add(visit);.
Or you will save as a graph like Shyju explained.

How do I use an edit viewmodel in MVC?

I have been struggling with this for some time. I have a model and an edit view model so I can allow the user to both see the image that was uploaded before and upload a replacement. Everything works fine until I get to the db.Entry portion. The error is:
The entity type EditCardViewModel is not part of the model for the current context.
If I try to add EditCardViewModel to the DbContext, it wants a key and a table, which isn't going to happen. The ViewModel is just a way to pass data. How do I tell it to use the Cards context when saving from this ViewModel?
Controller Edit Get:
public ActionResult Edit(int id = 0)
{
Card card = db.Cards.Find(id);
ViewData["Abilities"] = card.CardAbilities.Select(a => a.AbilityID);
if (card == null)
{
return HttpNotFound();
}
var editview = new EditCardViewModel(card);
{
}
return View(editview);
}
Controller Edit Post:
[HttpPost]
public ActionResult Edit(EditCardViewModel card)
{
if (ModelState.IsValid)
{
if(card.ImageUpload != null)
{
string savedFileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Images");
savedFileName = Path.Combine(savedFileName, Path.GetFileName(card.ImageUpload.FileName));
card.ImageUpload.SaveAs(savedFileName);
card.Cards.ImageUrl = "\\Images\\" + Path.GetFileName(card.ImageUpload.FileName);
}
db.Entry(card).State = EntityState.Modified; //ERROR - Entity Type is not part of context
db.SaveChanges();
Edit ViewModel:
public class EditCardViewModel
{
public Card Cards { get; set; }
public HttpPostedFileBase ImageUpload { get; set; }
public IEnumerable<SelectListItem> Abilities { get; set; }
public int[] SelectedAbilities { get; set; }
public IEnumerable<SelectListItem> Rarities { get; set; }
public int SelectedRarities { get; set; }
public IEnumerable<SelectListItem> MainTypes { get; set; }
public int SelectedMainTypes { get; set; }
public IEnumerable<SelectListItem> SubTypes { get; set; }
public int SelectedSubTypes { get; set; }
public IEnumerable<SelectList> CardSets { get; set; }
public int SelectedCardSets { get; set; }
public Rarity Rarity { get; set; }
public MainType MainType { get; set; }
public SubType SubType { get; set; }
public CardSet CardSet { get; set; }
public EditCardViewModel() { } //NEEDED OR PARAMETERLESS CONSTRUCTOR ERROR
public EditCardViewModel(Card card) //NEEDED OR CANNOT PASS CARD MODEL
{
Cards = card;
}
}
The problem is that your view model is not recognised by Entity Framework - it has no idea that EditCardViewModel is meant to be a representation of a Card. It's a bit unclear from your view model exactly what you are doing with it but you either need to create a new Card object and use that:
var newCard = new Card
{
Id = card.Id //for example
};
Or possibly use the Cards property of your view model as that is of the correct type.

Reloading model in mvc

I want get some qualification about reloading model in mvc action. For example:
I have some class model:
public class PresentationItemModel()
{
public int Id { get; set; }
public string Name { get; set; }
public string Title { get; set; }
public string Type { get; set; }
public List<int> PresentationIdList { get; set; }
}
And some controller action:
public ActionResult PostAction(PresentationItemModel model)
{
...
if(model.PresentationIdList == null)
{
model.PresentationIdList = new List<int>();
}
model.PresentationIdList.Add(model.Id);
...
...
...
}
I can call PostAction method several times and I want to save model.PresentationIdList result with all id's. But every time my PresentationIdList reloading with all model. But it's standard behavior.
Can I resolve it?
All you need to do is return the model object from your PostAction:
public ActionResult PostAction(PresentationItemModel model)
{
...
if(model.PresentationIdList == null)
{
model.PresentationIdList = new List<int>();
}
model.PresentationIdList.Add(model.Id);
...
...
...
return new ActionResult(model);
}

Partial Updates for Entities with Repository/DTO patterns in MVC (prepping for API)

I've built my Domain model layer, my repository layer, and now I'm working on my DTO layer to be used by a webApi project. I'm in the middle of implementing an Update service method, and I'm wondering about partial updates. Here's my DTO class:
public class FullPersonDto
{
public FullPersonDto()
{
Friends = new List<Person>();
}
public FullPersonDto(Person person)
{
PersonId = person.PersonId;
DateCreated = person.DateCreated;
Details = person.Details;
Friends = new List<Person>();
foreach (Person friend in person.Friends)
{
Friends.Add(new PersonDto(friend));
}
}
[Key]
public int PersonId { get; set; }
[Required]
public virtual DateTime DateCreated { get; set; }
public virtual string Details { get; set; }
public List<Person> Friends { get; set; }
public Person ToEntity()
{
var person = new Person
{
PersonId = PersonId,
DateCreated = (DateTime) DateCreated,
Details = Details,
Friends = new List<Person>()
};
foreach (PersonDto friend in Friends)
{
person.Friends.Add(friend.ToEntity());
}
return person;
}
}
Here's my Update method in my Repository:
public Person UpdatePerson(Person person)
{
var entry = _db.Entry(person);
if (entry.State == EntityState.Detached)
{
var dbSet = _db.Set<Person>();
Person attachedPerson = dbSet.Find(person.PersonId);
if (attachedPerson != null)
{
var attachedEntry = _db.Entry(attachedPerson);
attachedEntry.CurrentValues.SetValues(person); // what if values are null, like ID, or DateCreated?
}
else
{
entry.State = EntityState.Modified;
}
}
SaveChanges();
return person;
}
My question is: What if I only need to update the Details of a person via my webAPI? Is the convention to construct an entire PersonDto and Update the entire object using SetValues, or is there any way I can specify that I only want a single field updated so that I don't have to send a ton of data over the wire (that I don't really need)?
If it is possible to do partial updates, when is it ever good to update the entire entity? Even if I have to update 5/7 properties, it requires that I send old data for 2/7 to re-write so that SetValues doesn't write nulls into my fields from my DTO.
Any help here would be awesome... totally new to this stuff and trying to learn everything right. Thank you.
I've taken similar approach to do optimization, and I've faced same issues with null values when attaching (not just null, you'll have issue with boolean as well). This is what I've come up with:
public static void Update<T>(this DbContext context, IDTO dto)
where T : class, IEntity
{
T TEntity = context.Set<T>().Local.FirstOrDefault(x => x.Id == dto.Id);
if (TEntity == null)
{
TEntity = context.Set<T>().Create();
TEntity.Id = dto.Id;
context.Set<T>().Attach(TEntity);
}
context.Entry(TEntity).CurrentValues.SetValues(dto);
var attribute = dto.GetAttribute<EnsureUpdatedAttribute>();
if (attribute != null)
{
foreach (var property in attribute.Properties)
context.Entry(TEntity).Property(property).IsModified = true;
}
}
That is extension method for DbContext. Here are the interfaces IDTO and IEntity:
public interface IDTO
{
int Id { get; set; }
}
public interface IEntity
{
int Id { get; set; }
Nullable<DateTime> Modified { get; set; }
Nullable<DateTime> Created { get; set; }
}
I'm using my custom EnsureUpdatedAttribute to annotate what properties should always be updated (to deal with nulls / default values not being tracked):
public class EnsureUpdatedAttribute : Attribute
{
public IEnumerable<string> Properties { get; private set; }
public EnsureUpdatedAttribute(params string[] properties)
{
Properties = properties.AsEnumerable();
}
}
And this is a sample of usage:
public class Sample : IEntity
{
public int Id { get; set; }
public string Name { get; set; }
public bool Active { get; set; }
public Nullable<DateTime> Modified { get; set; }
public Nullable<DateTime> Created { get; set; }
}
[EnsureUpdated("Active")] /// requirement for entity framework change tracking, read about stub entities
public class SampleDTO : IDTO
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
[JsonIgnore] /// How to exclude property from going on the wire / ignored for serialization
public bool Active { get; set; }
}
[HttpPost]
public HttpResponseMessage SaveSample(SampleDTO dto)
{
dto.Active = true;
_ctx.AddModel<Sample>(dto);
_ctx.SaveChanges();
return NoContent();
}
return NoContent() is just extension for returning 204 (NoContent).
Hope this helps.
Theres a few options you have, you can create a stored procedure to update the required parts (I wouldnt do this), or you can manually select the fileds to update on the model before saving the context changes with EF.
Heres an example how to update a specific field:
public void UpdatePerson(int personId, string details)
{
var person = new Person() { Id = personId, Details = details };
db.Persons.Attach(personId);
db.Entry(person).Property(x => x.Details).IsModified = true;
db.SaveChanges();
}
It will depend on your scenario what you want to do, but generally speaking its fine to send your whole entity to be updated, and this is how i would approach your situation potentially changing in the future if needed.

Resources