Delete row ASP.NET MVC ADO.NET entity Model - c#

I'm kinda newbie with asp.net MVC environment
i'm trying to delete ROW from 3 table/entity(cause i'm using ado.net entity data model to generate the database automatically) the problem is when my delete function is executed only ROW from 1 table is deleted..
PS: i've also already create the relationship between 3 table
here is my controller:
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(int id)
{
// i've edited this code, i think the problem lies in this code bellow
// start edited code
ms_student ms_student = db.ms_student
.Include(i => i.ms_person)
.Include(i => i.ms_person.ms_user)
.Where(i => i.user_id_student == id)
.Single();
// end edited code
db.ms_student.Remove(ms_student);
db.SaveChanges();
return RedirectToAction("Index");
}
this is my ms_user model:
namespace test.Models
{
using System;
using System.Collections.Generic;
public partial class ms_user
{
public int ID { get; set; }
public string password { get; set; }
public string salt { get; set; }
public Nullable<int> administrative_type_id { get; set; }
public string email_login { get; set; }
public virtual ms_person ms_person { get; set; }
}
}
this is ms_person model:
namespace test.Models
{
using System;
using System.Collections.Generic;
public partial class ms_person
{
public int ID { get; set; }
public Nullable<int> family_id { get; set; }
public string first_name { get; set; }
public string last_name { get; set; }
public string email { get; set; }
public string address { get; set; }
public string phone_address { get; set; }
public string mobile_phone_number { get; set; }
public string gender { get; set; }
public Nullable<System.DateTime> date_of_bith { get; set; }
public Nullable<System.DateTime> date_start { get; set; }
public Nullable<System.DateTime> date_end { get; set; }
public string status { get; set; }
public string identification_ID { get; set; }
public string passport { get; set; }
public Nullable<int> user_type_id { get; set; }
public string file_image { get; set; }
public virtual ms_student ms_student { get; set; }
public virtual ms_user ms_user { get; set; }
}
}
Lastly my ms_person model:
namespace test.Models
{
using System;
using System.Collections.Generic;
public partial class ms_student
{
public int user_id_student { get; set; }
public int student_code { get; set; }
public int course_id { get; set; }
public string degree { get; set; }
public Nullable<int> current_semester { get; set; }
public string cuti_session { get; set; }
public virtual ms_person ms_person { get; set; }
}
}
just you know that the model code is auto generated, i'm using ado.net entity model and the only table/entity that deleted are only the ms_student table(sorry, i'm kinda confused with naming: model or entity or table)
the ID on ms_person are auto increment PK
the ID on ms_user actually the FK also the PK of ms_person
and (foolishly of me for the different naming) user_id_student actually the FK also the PK of ms_person
thank you very much

I think i just found some solution,
i change my delete controller with this:
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(int id)
{
// i change this piece of code, not really sure what it means though
// very appreciate if somebody can describe it in more humanly or sql language
ms_person ms_person = db.ms_person
.Include(i => i.ms_student)
.Include(i => i.ms_user)
.Where(i => i.ID == id)
.Single();
db.ms_person.Remove(ms_person);
db.SaveChanges();
return RedirectToAction("Index");
}
with this all the record from 3 table is deleted, but i'm not sure this is the best solution, because as you can see i just modified the Include() statement, and i'm not really sure this method can be used on other controller as well...
thank you very much, fell free if somebody can put a better solution for my problem.. :D

You want to also remove the ms_person and ms_user?
Do this.
db.ms_student.Remove(ms_student);
if (ms_student.ms_person != null)
{
db.ms_person.Remove(ms_student.ms_person);
if (ms_student.ms_person.ms_user != null)
{
db.ms_user.Remove(ms_student.ms_person.ms_user);
}
}
db.SaveChanges();

[HttpGet]
public ActionResult DeleteFacilitator( Int64 FacID)
{
if(FacID == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var Resul= db.NFE_Facilitator.Find(ID);
if(Resul==null)
{
return HttpNotFound();
}
return View(Resul);
}
[HttpPost,ActionName("DeleteFacilitator")]
public ActionResult DeleteConfirmed( Int64 ID)
{
var Resul= db.NFE_Facilitator.Find(ID);
db.NFE_Facilitator.Remove(Resul);
db.SaveChanges();
return RedirectToAction("SearchFacilitator");
}

Related

net core asp with automatic create and update data field

I have a problem with EF and MVC on net core.
I have an "item" model. This model has the required "createdate" and "updateDate" fields (I can't have a record without having the record date).
I use both fields with inheritance over BaseEntity.
The point is that to assign these dates, I do it directly in the context, overriding the "SaveChanges" function.
Because of this, by not giving it a value in either the view or the controller, the model evaluation fails because the dates are null. I actually give it value but after passing validation.
What do you think would be the most correct solution?
This is my model:
public class ItemType : BaseEntity
{
[Key]
public int Id { get; set; }
[Required]
public string Description { get; set; }
public ICollection<Item> Items { get; set; }
public int SizeTypeId { get; set; }
public SizeType SizeType { get; set; }
}
public class BaseEntity
{
[Required]
public bool Active { get; set; }
public DateTime? DeleteDate { get; set; }
public DateTime CreatedDate { get; set; }
public DateTime UpdatedDate { get; set; }
public string Comments { get; set; }
}
this is my savechanges override:
public override int SaveChanges()
{
var entries = ChangeTracker
.Entries()
.Where(e => e.Entity is BaseEntity && (
e.State == EntityState.Added
|| e.State == EntityState.Modified));
foreach (var entityEntry in entries)
{
((BaseEntity)entityEntry.Entity).UpdatedDate = DateTime.Now;
if (entityEntry.State == EntityState.Added)
{
((BaseEntity)entityEntry.Entity).CreatedDate = DateTime.Now;
}
}
return base.SaveChanges();
}
this is my controller:
public async Task<IActionResult> Create([Bind("Id,Description,Active,DeleteDate,CreatedDate,UpdatedDate,Comments")] SizeType sizeType)
{
if (ModelState.IsValid)
{
_context.Add(sizeType);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(sizeType);
}
Thanks you very much!!
One easy option would be to just make the properties nullable i.e. DateTime? CreatedDate since the entity isn't already created or deleted it makes sense for the CreatedDate or UpdatedDate properties to be null. However, a better option is to just create a DTO or in other words, a ViewModel that wraps the data of your entity and exposes it to the View. For example:
public class ItemTypeRequest : BaseEntityRequest
{
[Required]
public string Description { get; set; }
public ICollection<Item> Items { get; set; }
public int SizeTypeId { get; set; }
public SizeType SizeType { get; set; }
}
public class BaseEntityRequest
{
[Required]
public bool Active { get; set; }
public string Comments { get; set; }
}
Normally in a well-defined ViewModel, you are exposing to the View only the minimal set of data that is needed to perform the operation. In this case the Create View does not need an Id, CreatedDate, or UpdatedDate, because the entity isn't already created i.e. it does not exist in the database and therefore has no Id or creation date. After creating the ViewModels you can leverage AutoMapper to map the ViewModels data to the entity data
var config = new MapperConfiguration(cfg => {
cfg.CreateMap<ItemTypeRequest , ItemType>();
cfg.CreateMap<ItemType, ItemTypeResponse>();
});
var mapper = config.CreateMapper();
public async Task<IActionResult> Create(ItemTypeRequest itemTypeRequest)
{
if (ModelState.IsValid)
{
ItemType itemType = mapper.Map<ItemType>(itemTypeRequest);
_context.Add(itemType);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View();
}
Following the same login, you should create a response DTO/ViewMode this time with more data if you need it i.e.
public class ItemTypeResponse : BaseEntityResponse
{
public int Id { get; set; }
public string Description { get; set; }
public ICollection<Item> Items { get; set; }
public int SizeTypeId { get; set; }
public SizeType SizeType { get; set; }
}
public class BaseEntityResponse
{
public bool Active { get; set; }
public DateTime CreatedDate { get; set; }
public DateTime UpdatedDate { get; set; }
public string Comments { get; set; }
}
This time the properties CreatedDate and UpdatedDate are included since they have values after you have created the entity.

MVC4: Retrieving a related list with Entity and casting it as List<> or IEnum<> for View Model

This a simple project where users can search for job postings by area of expertise. The relationship between Areas and Postings are Many-to-many. I seem to be able to get to the very last part of retrieving the correctly filtered list, but getting back into the view model keeps giving me different errors:
ViewModel:
public class AreaOfertasViewModel
{
public Oferta UnaOferta { get; set; }
public SelectList AreasTrabajo { get; set; }
public IEnumerable<Oferta> Ofertas { get; set; }
public int idArea { get; set; }
public AreaOfertasViewModel()
{
this.UnaOferta = UnaOferta;
this.Ofertas = new List<Oferta>();
cargarAreas();
}
private void cargarAreas()
{
PostulaOfertaContext db = new PostulaOfertaContext();
this.AreasTrabajo = new SelectList(db.Areas, "areaId", "Area");
}
}
}
Controller:
public ActionResult SearchXArea()
{
return View(new AreaOfertasViewModel());
}
[HttpPost]
public ActionResult SearchXArea(AreaOfertasViewModel aovm)
{
int id = aovm.idArea;
PostulaOfertaContext db = new PostulaOfertaContext();
var area = db.Areas.Where(c => c.areaId == id);
var ofertas = from c in db.Ofertas.Where(r => r.AreaTrabajo == area)
select c;
aovm.Ofertas = (IEnumerable<Oferta>)ofertas.ToList();
return View(aovm);
}
The line giving me issues is
aovm.Ofertas = (IEnumerable)ofertas.ToList();
I've tried List<> for Ofertas, and I've tried leaving it as .ToList() without casting, and casting it as different things, but it gives me errors about not being able to cast it, and "Cannot compare elements of type 'System.Collections.Generic.List`1'. Only primitive types, enumeration types and entity types are supported."
What's the solution here?
Model for AreaTrabajo:
public class AreaTrabajo
{
[Key]
public int areaId { get; set; }
public string Area { get; set; }
public virtual List<Oferta> oferta { get; set; }
}
Model for Oferta:
public class Oferta
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
public string Titulo { get; set; }
[Required]
public DateTime Vencimiento { get; set; }
[Required]
public string Cargo { get; set; }
[Required]
public int HorarioComienzo { get; set; }
[Required]
public int HorarioFin { get; set; }
[Required]
public string DescripcionTareas { get; set; }
public int Remuneracion { get; set; }
[Required]
public int RangoEdadMin { get; set; }
[Required]
public int RangoEdadMax { get; set; }
public string TipoFormacion { get; set; }
public string Idiomas { get; set; }
public string Competencias { get; set; }
public string OtrosEstudios { get; set; }
public string Estado { get; set; }
public virtual List<AreaTrabajo> AreaTrabajo { get; set; }
public virtual TipoContrato TipoContrato { get; set; }
public virtual Empresa Empresa { get; set; }
public virtual List<Postulante> Postulantes { get; set; }
}
Answer
[HttpPost]
public ActionResult SearchXArea(AreaOfertasViewModel aovm)
{
int id = aovm.idArea;
PostulaOfertaContext db = new PostulaOfertaContext();
var area = db.Areas.Where(c => c.areaId == id).FirstOrDefault();
var ofertas = db.Ofertas.Where(s => s.AreaTrabajo.All(e => e.areaId == area.areaId)).ToList();
aovm.Ofertas = ofertas;
return View(aovm);
}
Sorry if my question wasn't clear enough. I needed to filter out from the many-to-many relationship, and this solved it.
You are getting an error because the actual sql is executed when you call tolist(). The error is in your sql because you are comparing AreaTrabago to a list.
[HttpPost]
public ActionResult SearchXArea(AreaOfertasViewModel aovm)
{
int id = aovm.idArea;
PostulaOfertaContext db = new PostulaOfertaContext();
var area = db.Areas.Where(c => c.areaId == id).FirstOrDefault();
var ofertas = db.Ofertas.Where(s => s.AreaTrabajo.All(e => e.areaId == area.areaId)).ToList();
aovm.Ofertas = ofertas;
return View(aovm);
}
Sorry if my question wasn't clear enough. I couldn't get the many-to-many relationship, and this solved the filtering problem perfectly.

How to load DTO Within DTOs?

PROBLEM:
I am very new to EF and to LINQ, so please bear with me.
I am trying to create a EF6 model using the database first approach. Simply speaking, I have 2 database tables tblUser and tblMilkMan which have a foreign key relationship on the UserID column.
To avoid cyclic references and to shape the entity data I have created DTO classes for both the models.
I made the MilkManDTO class contain a reference to a UserDTO instance.(This is probably stupid, if so, please guide me to the right way).My aim is to be able to load a milkmen and the related User data
Anyway in my API call, when I try to load a MilkMan by ID, I do not know how to load the related UserDTO. I found examples online on how to load related Entities but not related DTOs.
DB Schema:
Models:
MilkMan Model and DTO:
namespace MilkMan.Models
{
using System;
using System.Collections.Generic;
public partial class tblMilkMan
{
public int RecordID { get; set; }
public int UserID { get; set; }
public bool IsMyTurn { get; set; }
public int RoundRobinOrder { get; set; }
public virtual tblUser tblUser { get; set; }
}
public class MilkManDTO
{
public int RecordID { get; set; }
public int UserID { get; set; }
public bool IsMyTurn { get; set; }
public int RoundRobinOrder { get; set; }
public virtual UserDTO User { get; set; }
}
}
User Model and DTO:
public partial class tblUser
{
public tblUser()
{
this.tblMilkMen = new HashSet<tblMilkMan>();
}
public int UserID { get; set; }
public string LogonName { get; set; }
public string Password { get; set; }
public int PasswordExpiresAfter { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
:
// more fields
:
public virtual ICollection<tblMilkMan> tblMilkMen { get; set; }
}
public class UserDTO
{
public int UserID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
Web API Controller Method:
// GET api/MilkMan/5
[ResponseType(typeof(MilkManDTO))]
public async Task<IHttpActionResult> GettblMilkMan(int id)
{
//tblMilkMan tblmilkman = await db.tblMilkMen.FindAsync(id);
MilkManDTO milkMan = await db.tblMilkMen.Select(b => new MilkManDTO()
{
RecordID = b.RecordID,
UserID = b.UserID,
IsMyTurn = b.IsMyTurn,
RoundRobinOrder = b.RoundRobinOrder,
User = //???? Error//
}).SingleOrDefaultAsync(b => b.RecordID == id);
if (milkMan == null)
{
return NotFound();
}
return Ok(milkMan);
}
You can nest a new UserDTO and use the same initialization list technique.
MilkManDTO milkMan = await db.tblMilkMen.Select(b => new MilkManDTO()
{
RecordID = b.RecordID,
UserID = b.UserID,
IsMyTurn = b.IsMyTurn,
RoundRobinOrder = b.RoundRobinOrder,
User = new UserDTO {
UserID = b.User.UserID,
FirstName = b.User.FirstName,
LastName = b.User.LastName,
}
}).SingleOrDefaultAsync(b => b.RecordID == id);
This code may throw a null reference exception on b.User.UserID if there is not associated User and thus User could be null. You would need to deal with this with either a ?? coalesce, ternary (b.User == null ? "DefaultFirstName" : b.User.FirstName) or omit the entire reference User = (b.User == null ? (UserDTO)null : new UserDTO { ... }). null's make this kind of thing fun.
With C# 6 we have null reference operator .? that makes this much more succinct.

Entity Framework: Navigational properties - Code First

Man I am having a heck of a time today trying to get this to work. I think I'm missing something in terms of a navigational property.
My controller. When I put a breakpoint at foo = 5, and I look at the local watch window, "listOfComments" has zero elements even though my database has the information listed(see below)
public ActionResult CommentsList()
{
var post = _db.GetPost(5);
List<Comment> listOfComments = post.Comments.ToList();
var foo = 5;
return View(post);
}
GetPost method
public Post GetPost(int? postId)
{
var context = DataContext;
var post = context.Posts.FirstOrDefault(x => x.Id == postId);
if (post == null)
{
return new Post();
}
return post;
}
Comment class
public class Comment
{
public int Id { get; set; }
[Required]
public DateTime Date { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string Email { get; set; }
[Required]
public string Body { get; set; }
//Navigational
public Post Post { get; set; }
}
Post class
public class Post
{
public Post()
{
Comments = new HashSet<Comment>();
Tags = new HashSet<Tag>();
}
public int Id { get; set; }
[Required]
public string Title { get; set; }
[Required]
public DateTime Date { get; set; }
[Required]
public string Body { get; set; }
//Navigational
public ICollection<Comment> Comments { get; set; }
public ICollection<Tag> Tags { get; set; }
}
My DbContext class
public class HundredBlog: DbContext
{
public HundredBlog() : base("HundredBlog") { }
public DbSet<Post> Posts { get; set; }
public DbSet<Comment> Comments { get; set; }
public DbSet<Administrator> Administrators { get; set; }
public DbSet<Tag> Tags { get; set; }
}
The Database table, "Comments" has the following columns:
-Id
-Date
-Name
-Email
-Body
-Post_Id
The Database table, "Posts" has the following columns:
-Id
-Title
-Date
-Body
Just as an example, my Database populates the Comments columns just fine, it adds the right Post_Id referencing the primary key and all. I have the same issue with the Tag table, but that even has it's own reference table:
The Database table, "TagPosts" has the following columns:
-TagId
-PostId
Lost please help!
The Comments collection in the Post class should be virtual if you want to enable lazy loading or you should use Include(p => p.Comments) to load the data with the original query. In general the second option is better.

NullReferenceException thrown by MVC View Model

I'm trying to sort out this issue but as I'm learning a lot of this stuff as I go along I'd really appreciate it if someone could explain where I'm going wrong and/or some good resources where I can read up.
So, I have a model based on my Entity Framework model of my database and a viewmodel representing properties in that model. I've built a Kendo grid to display the data (defined in a js file) and the method in the contoller returns a Json result set. Trouble is, when I try to display a value in a joined db table, if there hasn't been a key value set, I get a nullreferenceexception error. Obviously I'm missing part of the puzzle here as there must be a way of coding this to stop it happening. Any help would be gratefully received!
My model is like this:
namespace TrainingKendoUI.Models
{
using System;
using System.Collections.Generic;
public partial class TRAINING_EMPLOYEE_COURSES
{
public int EMP_COURSE_ID { get; set; }
public int EMPLOYEE_ID { get; set; }
public int COURSE_ID { get; set; }
public Nullable<System.DateTime> DATE_ATTENDED { get; set; }
public Nullable<decimal> COURSE_COST { get; set; }
public string COURSE_RESITS { get; set; }
public Nullable<int> PROVIDER_ID { get; set; }
public Nullable<int> EMP_COURSE_STATUS_ID { get; set; }
public Nullable<int> VENUE_ID { get; set; }
public virtual TRAINING_COURSES TRAINING_COURSES { get; set; }
public virtual TRAINING_EMPLOYEE_COURSE_STATUS TRAINING_EMPLOYEE_COURSE_STATUS { get; set; }
public virtual TRAINING_EMPLOYEES TRAINING_EMPLOYEES { get; set; }
public virtual TRAINING_PROVIDERS TRAINING_PROVIDERS { get; set; }
public virtual TRAINING_VENUES TRAINING_VENUES { get; set; }
}
}
My controller method looks like this:
public JsonResult EmployeeCourses_Read()
{
var model = db.TRAINING_EMPLOYEE_COURSES;
var ViewModel = new List<EmployeeCoursesIntersectionViewModel>();
foreach (var employee in model)
{
ViewModel.Add(new EmployeeCoursesIntersectionViewModel(employee));
}
return Json(ViewModel, JsonRequestBehavior.AllowGet);
}
and my view model lilke this:
namespace TrainingKendoUI.ViewModels
{
public class EmployeeCoursesIntersectionViewModel
{
#region Constructors
public EmployeeCoursesIntersectionViewModel()
{
}
public EmployeeCoursesIntersectionViewModel(TRAINING_EMPLOYEE_COURSES model)
{
this.empCourseId = model.EMP_COURSE_ID;
this.employee = model.TRAINING_EMPLOYEES.FIRST_NAME;
this.course = model.TRAINING_COURSES.COURSE_NAME;
this.dateAttended = model.DATE_ATTENDED;
this.cost = model.COURSE_COST;
this.resits = model.COURSE_RESITS;
//These lines will produce a NullReference error if not set through the front end...
this.provider = model.TRAINING_PROVIDERS.PROVIDER_NAME;
this.status = model.TRAINING_EMPLOYEE_COURSE_STATUS.EMP_COURSE_STATUS;
this.venue = model.TRAINING_VENUES.VENUE_NAME;
}
#endregion
#region Properties
public int empCourseId { get; set; }
public string employee { get; set; }
public string course { get; set; }
public Nullable<System.DateTime> dateAttended { get; set; }
public Nullable<decimal> cost { get; set; }
public string resits { get; set; }
public string provider { get; set; }
public string status { get; set; }
public string venue { get; set; }
#endregion
}
}
Do a null check on the object before setting it, i.e.
this.provider = model.TRAINING_PROVIDERS == null ? ""
: model.TRAINING_PROVIDERS.PROVIDER_NAME;
and you'll have to do similar for status and venue
this.status = model.TRAINING_EMPLOYEE_COURSE_STATUS== null ? ""
model.TRAINING_EMPLOYEE_COURSE_STATUS.EMP_COURSE_STATUS;
this.venue = model.TRAINING_VENUES== null ? ""
model.TRAINING_VENUES.VENUE_NAME;

Categories

Resources