Check value prior to form submit in POST controller - asp.net

Sorry if the subject is inaccurate, but basically upon submit of a Form I want to compare the previous value of the model's Foreign Key.
My model is:
public class Booking
{
public int ID { get; set; }
[ForeignKey("Store")]
public int StoreID { get; set; }
public virtual Store Store { get; set; }
public string BookedBy { get; set; }
public DateTime? DateBooked { get; set; }
public string Description { get; set; }
public DateTime FromDate { get; set; }
public DateTime ToDate { get; set; }
public string Status { get; set; }
}
After editing a booking in Edit view and submitting, I want to check if the StoreID has been modified, so that I can perform a required action.
I was creating an instance of Booking as oldBooking and then comparing StoreID with booking.StoreID passed back from View, but this created an Attach error when I saved the Edited form.
Any suggestions?
Edited 27/1/15:
public ActionResult Edit([Bind(Include = "ID,StoreID,BookedBy,DateBooked,Agreement,Description,FromDate,ToDate")] Booking booking, string returnURL)
{
if (ModelState.IsValid)
{
Booking oldBooking = db.Bookings.Find(booking.ID);
int prevStoreID = oldBooking.StoreID;
db.Entry(booking).State = EntityState.Modified;
db.SaveChanges();
if(prevStoreID == booking.StoreID)
{
sendStoreChangeEmail(prevStoreID, booking.StoreID);
}
return RedirectToAction("Index", "Home", null);
}
ViewBag.StoreID = new SelectList(db.Stores, "ID", "ID", booking.StoreID);
return View(booking);
}
When attempt to update db entry state I get this error:
"Attaching an entity of type 'uatlab2.Models.Booking' failed because another entity of the same type already has the same primary key value. This can happen when using the 'Attach' method or setting the state of an entity to 'Unchanged' or 'Modified' if any entities in the graph have conflicting key values. This may be because some entities are new and have not yet received database-generated key values. In this case use the 'Add' method or the 'Added' entity state to track the graph and then set the state of non-new entities to 'Unchanged' or 'Modified' as appropriate."

After reading a couple of other posts and googling 'detach', i read this article:
ASP MVC How to update DB entry with collections field
and after I have got prevStoreID do this:
((IObjectContextAdapter)db).ObjectContext.Detach(oldBooking);
And it works.
Thanks for your help and inspiration.
C

Related

ASP.NET Razor - How to create a POST form for List of objects?

I need to create a POST form to add new objects to database. I have to create a Razor page where I can add new lesson form on click of a button. And after it on click of another button all the lessons should be added to DB context. I still don't know how to do it so I want you to help me
public class Course
{
public Guid Id { get; set; }
public string Category { get; set; }
public string Title{ get; set; }
public List<Lesson> Lessons { get; set; } = new List<Lesson>();
}
public class Lesson
{
public Guid Id { get; set; }
public string Title { get; set; }
public string Text { get; set; }
}
Here is some image of what I mean:
DB has a Course table and a Lesson table. Please tell me how I can create a page to create new 'Course' with dynamic amount of 'Lessons'
Please try with this in your controller method you need to pass from the page.
public ActionResult PostMethod(Course course, FormCollection formCollection)
{
string title = course.Title; // Title value
string category = course.Category; // Category value
//add course into database
if (course.Lessons != null && course.Lessons.Count > 0)
{
foreach (var item in course.Lessons)
{
//add Lessons into database
}
}
}
Please note in this example you are going to perform many operations in databases
you have to manage transaction as well for this.
Using Transactions or SaveChanges(false) and AcceptAllChanges()?

InvalidOperationException: The entity type 'Array' requires a primary key to be defined

I am making a Web API with .Net and it is receiving a custom JSON object from a web form to serialize to the model. I am currently having an issue displaying the API response. I am storing the data in an in memory database at first just to get it working.
I am not sure why it is asking me for a primary key despite there being a key defined on my model.
My next step is to add multipart-form data but that is its own can of worms.
The error happens on the _context.ProjectItems.ToListAsync(); line.
I have already added an ID to the model.
[Required]
[Key]
public new long Id { get; set; }
[HttpGet("{id}")]
public async Task<ActionResult<ProjectItem>> GetProjectItem(long id)
{
var projectItem = await _context.ProjectItems.FindAsync(id);
if (projectItem == null)
{
return NotFound();
}
return projectItem;
}
[HttpGet]
public async Task<ActionResult<IEnumerable<ProjectItem>>>
GetProjectItems()
{
return await _context.ProjectItems.ToListAsync();
}
My model: ProjectItem.cs
using System.ComponentModel.DataAnnotations;
namespace RupAPI.Controllers
{
public class ProjectItem : Project
{
[Required]
[Key]
public new long Id { get; set; }
public string ProjName { get; set; }
public DateTime DateSub { get; set; }
public DateTime DueDate { get; set; }
public DateTime ArrivalDate { get; set; }
public string Desc { get; set; }
public Array Sku { get; set; }
public Array SkuDesc { get; set; }
public Array Item { get; set; }
public Array ItemDesc { get; set; }
public Array FileName { get; set; }
public new byte[] File { get; set; }
}
}
An unhandled exception occurred while processing the request. InvalidOperationException: The entity type 'Array' requires a primary key to be defined.
Microsoft.EntityFrameworkCore.Infrastructure.ModelValidator.ValidateNonNullPrimaryKeys(IModel model)
Stack Query Cookies Headers
InvalidOperationException: The entity type 'Array' requires a primary key to be defined.
+
return await _context.ProjectItems.ToListAsync();
lambda_method(Closure , object )
Reconsider the usage of Array as type for your properties, which cause this issue.
If those properties are really more than just string, create additional model(s) to represent the properties and use relationships to store them in your database.
If the properties are lists of strings, there are several solutions proposed here. If possible I would go for Sasan's solution, which is for your case to replace Array with string[] and add
modelBuilder.Entity<ProjectItem>()
.Property(e => e.Sku)
.HasConversion(
v => string.Join(',', v),
v => v.Split(',', StringSplitOptions.RemoveEmptyEntries));
// TODO: also to that for the other properties
to your database context's OnModelCreating.

EF Core - Identity field suddenly jumped by 1000 and not able to search with Id

I am having a problem with primary key/Id of one table in a project.
In this table, the Id suddenly jumped from 38 to 1039.
Now the real issue is, when i find the entity by 1039 it doesn't exists but finding it by 39 gives me the entity.
I am not sure about this behaviour and hence not able to find the solution.
My model
public class Domain : Entity
{
public string Name { get; set; }
public string Description { get; set; }
}
public abstract class Entity
{
public int Id { get; set; }
public DateTime InsertDate { get; set; }
public DateTime? UpdateDate { get; set; }
public DateTime? DeleteDate { get; set; }
public bool IsDeleted { get; set; }
}
Method is like this...
public async Task<Response> Delete(int id)
{
var domain = await DataContext.Domains.FindAsync(id);
if (domain == null)
{
return new Response(ResponseType.NotFound);
}
}
Can anyone please help ?
it depend from Database setting IDENTITY-CACHE.
Identity cache store some values of a identity columns in case of SQL CRASH during a transaction or similar.
To avoid gaps in an identity column, you need to set IDENTITY-CACHE to OFF running this command on a SQL query window:
ALTER DATABASE SCOPED CONFIGURATION SET IDENTITY_CACHE = OFF
GO
you will find more informations here:
https://social.technet.microsoft.com/wiki/contents/articles/40666.sql-server-2017-identity-cache-feature.aspx

Reformat shown data

What's the easiest way to reformat data shown in the second view ?
I use .Net in the backend and Angular in the frontend.
I have a method that returns collection of attendances that has a collection of users with their statuses, and I can filter them to only query data in a date range.
I have no idea how to get the same data to get shown by users, since database structure is as follows:
Training has many schedules.
Schedules have Many Attendances.
Attendances have many Attendants and every Attendant has his status.
Now its easy to show data by attendances, but its impossible for me to figure out how to show data by attendants(users) to show all their attendances.
Is there any example someone could provide on something similar and how to do it in Asp, or angular.
I have tried creating new dto models, but I cant get neccessary data without using many queries, and mapping data too many times.
I have searched similar questions but didn't find anything relevant.
EDIT:
I am looking for the simplest solution.
I would like to know how to solve this both ways, and I can't decide which way is better ?
Here is the current method, which works for the first view:
public ICollection<AttendanceModel> ScheduleLog(int scheduleId, SearchAttendancesModel searchAttendances)
{
if (searchAttendances == null)
throw new ArgumentNullException("searchAttendances");
if (searchAttendances.Attendants == null)
throw new ArgumentNullException("searchAttendances.Attendants");
if (searchAttendances.AttendantStatuses == null)
throw new ArgumentNullException("searchAttendances.AttendantStatuses");
var query = _context
.Attendances
.Where(x=>x.ScheduleId==scheduleId)
.AsQueryable();
if (searchAttendances.FromDate != DateTime.MinValue)
{
query = query.
Where(x => x.Date >= searchAttendances.FromDate);
}
if (searchAttendances.ToDate != DateTime.MinValue)
{
query = query.
Where(x => x.Date <= searchAttendances.ToDate);
}
return query.ToList().Select(x => x.MapToAttendanceModel()).ToList();
}
It gets me the neccesary data to show for the first view, which I can easily show with tables thoru ng-repeat, but as I already said, I have many difficulties grouping data by user instead of by schedule, and then showing that data(all attendances per user) instead of all users per attendance.
Here is how my models look like:
This is schedule that has all the attendances:
public class ScheduleModel
{
public int Id { get; set; }
[Required]
public DateTime StartDate { get; set; }
[Required]
public DateTime EndDate { get; set; }
public string Description { get; set; }
public virtual ICollection<AttendanceModel> Attendances { get; set; }
}
This is attendance that has date for attendance and collection of attendants each of which have user and their status.
public class AttendanceModel
{
public int Id { get; set; }
[Required]
public DateTime Date { get; set; }
[Required]
public virtual ICollection<AttendantModel> Attendants { get; set; }
}
This is one Attendant that has user and status for that attendance
public class AttendantModel
{
public int Id { get; set; }
public virtual LookupModel ApplicantStatus { get; set; }
public virtual UserModel User { get; set; }
}

ASP.NET MVC 3 EntityType has no key defined

I want to display customer information.
Then I created some classes; Customer, Delivery, Order, OrderLine, Product, and rentalDB.
rentalDB class sets 5 DbSet of Product, Customer, Order, OrderLine, and Delivery.
When I make UserController with list view, I cannot display the customer information, and it takes errors:
One or more validation errors were detected during model generation:
System.Data.Edm.EdmEntityType: : EntityType 'OrderLine' has no key defined. Define the key for this EntityType.
System.Data.Edm.EdmEntityType: : EntityType 'Delivery' has no key defined. Define the key for this EntityType.
System.Data.Edm.EdmEntitySet: EntityType: EntitySet �OrderLine� is based on type �OrderLine� that has no keys defined.
System.Data.Edm.EdmEntitySet: EntityType: EntitySet �Delivery� is based on type �Delivery� that has no keys defined.
I don't know why these entities require key?
I have no idea for this error..
Could you help me?
--UserController.cs--
namespace MvcApplication2.Controllers
{
public class UserController : Controller
{
//
// GET: /User/
rentalDB _db = new rentalDB();
public ActionResult Index()
{
var model = _db.Customer;
return View(model);
}
}
}
--Delivery.cs in Models folder--
namespace MvcApplication2.Models
{
public class Delivery
{
public int trackId { get; set; }
public String address { get; set; }
public String postCode { get; set; }
public decimal deliveryPrice { get; set; }
public DateTime deliveryDate { get; set; }
public DateTime returnDate { get; set; }
}
}
--OrderLine.cs in Models folder--
namespace MvcApplication2.Models
{
public class OrderLine
{
public int basketId { get; set; }
public int productId { get; set; }
public int quantity { get; set; }
}
}
In order to use the entity framework, every entity needs a key. This is how EF tracks objects in its cache, posts updates back to the underlying data store, and links related objects together.
Yours objects already have keys, you just need to tell the EF about them:
namespace MvcApplication2.Models
{
public class Delivery
{
[Key] public int trackId { get; set; }
public String address { get; set; }
public String postCode { get; set; }
public decimal deliveryPrice { get; set; }
public DateTime deliveryDate { get; set; }
public DateTime returnDate { get; set; }
}
}
When you use an ORM (object-relational mapper) framework like NHibernate or Entity framework that helps you map a relational database to an object model you need something that will let you make a meaningful relation between your objects in memory and rows of data in your database and that thing is a key (id as NHibernate call it) and usually that's the natural way that RDBMS track records using a Primary key (usually you use DB primary key as the key of your object)
When you check to see if two objects are equal using == operator you are checking that those objects have the same reference (or address in memory). This kind of equality is not very helpful when you are using an ORM .You can load multiple instances of a record in memory with different references so that it's impossible to check the equality of objects by their references .That's when checking equality by value come into play and keys have the main role in this play.

Resources