Asp.net adding Values to Database - c#

Im new to asp.net and i started with basic crud operations.
I made the css class with db name values (code,name,price,currency) and DBcontext for this, when i made the controller it doesnt not add the values to the database but it's stored in somewhere.
When i use as a normal query from c# code, it's stored into the database.
My question is why does the CRUD operations from the (csfile and context) are not in the database?
--cs class--
public class Productos
{
[Key]
public int Codigo { get; set; }
public string Nombre { get; set; }
public decimal Precio { get; set; }
public string Moneda { get; set; }
}
-product context
public class ProductoContext : DbContext
{
public ProductoContext() : base("database name")
{
}
public DbSet<Productos> Producto { get; set; }
}
---this is the code to create---
// GET: Productos/Create
public ActionResult Create()
{
return View();
}
// POST: Productos/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "Codigo,Nombre,Precio,Moneda")] Productos productos)
{
if (ModelState.IsValid)
{
db.Producto.Add(productos);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(productos);
}
---- connection string------

Related

Add Strongly Typed List to Database

I am trying to add some entries to a database in a controllers HTTP post event. However I am getting the following error:
The entity type 'List' was not found. Ensure that the
entity type has been added to the model.
Code:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("ID,Name,Weight)] List<WBLoading> wBLoading)
{
if (ModelState.IsValid)
{
_context.Entry(wBLoading).State = EntityState.Modified;
await _context.SaveChangesAsync();
return RedirectToAction("Index");
}
return View(wBLoading);
}
I have added the table to the DbContext:
public DbSet<Models.WBLoading> WBLoading { get; set; }
Model:
public class WBLoading
{
public int ID { get; set; }
public string Name { get; set; }
public int Weight { get; set; }
}
You need to write the following code.
_context.WBLoading.add(wBLoading);
await _context.SaveChangesAsync();

SqlException: The INSERT statement conflicted with the FOREIGN KEY constraint

Hello and thank you in advance for taking time to read this post. I am new to EF Core and I am attempting to setup the following database connection where I have scaffold-ed controllers from the models.
namespace VotingWebApp.Models
{
public class QuestionObject
{
public int QuestionObjectID { get; set; }
public string Question { get; set; }
public string AnswerA { get; set; }
public string AnswerB { get; set; }
public int AnswerAVote { get; set; }
public int AnswerBVote { get; set; }
public int GroupItemID { get; set; }
public ICollection<ResponseItem> ResponseItems { get; set; }
public GroupItem GroupItem { get; set; }
}
}
namespace VotingWebApp.Models
{
public class GroupItem
{
public int GroupItemID { get; set; }
public string GroupName { get; set; }
public int MemberCount { get; set; }
public int Host { get; set; }
public ICollection<GroupUserLink> GroupUserLinks { get; set; }
public ICollection<QuestionObject> QuestionItems { get; set; }
}
}
I receive the following error when I attempt to create a new QuestionObject in the database (Even when I supply an existing GroupItem key).
SqlException: The INSERT statement conflicted with the FOREIGN KEY constraint "FK_QuestionObject_GroupItem_GroupItemID". The conflict occurred in database "aspnet-VotingWebApp-02945df4-961a-4b8f-8999-19aa61dfd02e", table "dbo.GroupItem", column 'GroupItemID'.
I am not sure how to go about solving this conflict. I have read other posts and they mainly highlight how the person is not supplying an existing key. I am new to EF Core so any help would be appreciated.
// GET: QuestionObjects/Create
public async Task<IActionResult> CreateQuestion(int? id)
{
if (id == null)
{
return NotFound();
}
var groupItem = await _context.GroupItem.SingleOrDefaultAsync(m => m.GroupItemID == id);
if (groupItem == null)
{
return NotFound();
}
QuestionObject questionObject = new QuestionObject();
questionObject.GroupItemID = groupItem.GroupItemID;
return View(questionObject);
}
// POST: QuestionObjects/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> CreateQuestion([Bind("AnswerA,AnswerAVote,AnswerB,AnswerBVote,GroupID,Question")] QuestionObject questionObject)
{
if (ModelState.IsValid)
{
_context.Add(questionObject);
await _context.SaveChangesAsync();
return RedirectToAction("Index");
}
return View(questionObject);
}
I have added the code for the insertion. This is within the GroupItem controller.
This looks more like a binding problem. First, your white list of included fields does not have GroupItemID so add it (unless GroupId was a typo):
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> CreateQuestion([Bind(Include="AnswerA,AnswerAVote,AnswerB,AnswerBVote,GroupID,GroupItemID,Question")] QuestionObject questionObject)
{
if (ModelState.IsValid)
{
_context.QuestionObjects.Add(questionObject);
await _context.SaveChangesAsync();
return RedirectToAction("Index");
}
return View(questionObject);
}
Next, you need to either have an input field or hidden field on your view for GroupItemID or it will come back null
#Html.HiddenFor(m => m.GroupItemID)
Try out populating GroupItem object on QuestionObject to help EF understand FK relationship.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> CreateQuestion([Bind("AnswerA,AnswerAVote,AnswerB,AnswerBVote,GroupID,Question")] QuestionObject questionObject)
{
if (ModelState.IsValid)
{
questionObject.GroupItem = _context.GroupItem.Single(m => m.GroupItemID == questionObject.GroupItemID)
_context.Add(questionObject);
await _context.SaveChangesAsync();
return RedirectToAction("Index");
}
return View(questionObject);
}

MVC5 custom authorize attribute against string in SQL table

I have read hundreds of articles on ASP.NET MVC Authorization attributes and i think i make it difficult than as it should be. I setup a class in ASP.NET identity as below:
public class UserDetails : IdentityUser
{
public virtual MembershipSerial MembershipSerial { get; set; }
}
public class MembershipSerial
{
[HiddenInput(DisplayValue=false)]
public int Id { get; set; }
[HiddenInput(DisplayValue=false)]
public string Serial { get; set; }
[Required]
[Display(Name="Membership Serial")]
public string SerialConfirmed { get; set; }
}
public class MyDbContext : IdentityDbContext<UserDetails>
{
public MyDbContext()
: base ("EFDbContext")
{
}
public System.Data.Entity.DbSet<MembershipSerial> MembershipSerial { get; set; }
}
I would like to achieve something like below with Authorize Attribute:
[AuthorizeUser(AccessLevels="Has a valid serial key and can place an order")]
public ActionResult PlaceOrder(int ProductID)
{
// some code...
return View();
}
[AuthorizeUser(AccessLevels="Has a valid login and can add items to cart")]
public ActionResult AddToCart(int ProductID)
{
// some code...
return View();
}
[AuthorizeUser(AccessLevels="Has no login and valid serialkey, anonymous ")]
public ActionResult Anonymous(int ProductID)
{
// some code...
return View();
}
Note: The property Serial is added by the system administrator and the property SerialConfirmed will be added by the user. The property SerialConfirmed should be compared to the Serial in the backend if the results where okay then should return true else false.
Is that possible? How?

Scaffolding ModelView creates underlying database tables

I'm trying to use ViewModels for the first time using AutoMapper. I have two models:
public class Item
{
public int ItemId { get; set; }
public bool Active { get; set; }
public string ItemCode { get; set; }
public string Name { get; set; }
public List<ItemOption> ItemOptions { get; set; }
//...
}
public class ItemOption
{
public int ItemOptionId { get; set; }
public string Name { get; set; }
public string Barcode { get; set; }
//...
}
Which I have turned into two ViewModels:
public class ItemDetailViewModel
{
public int ItemDetailViewModelId { get; set; }
public int ItemId { get; set; }
public bool Active { get; set; }
public string ItemCode { get; set; }
public string Name { get; set; }
public List<ItemDetailItemOptionViewModel> ItemOptions { get; set; }
}
public class ItemDetailItemOptionViewModel
{
public int ItemDetailItemOptionViewModelId { get; set; }
public int ItemOptionId { get; set; }
public string Name { get; set; }
public string Barcode { get; set; }
}
I then set the following in my application start-up:
Mapper.CreateMap<Item, ItemDetailViewModel>();
Mapper.CreateMap<ItemOption, ItemDetailItemOptionViewModel>();
Finally I scaffolded my ItemDetailViewModel:
I then built my project and added a new Item through /Item/Create
I had a look in the database expecting to see that I would have an entry in the Item table, but instead I have ItemDetailViewModel and ItemDetailItemOptionViewModel tables, which I wasn't expecting and the data is is ItemDetailViewModel.
I assume I have done something wrong with my scaffolding? How do I scaffold off the ViewModel without making it part of the main business models?
Further Details
If it isn't possible to scaffold the controller with a ViewModel, then how do I reference the ViewModel in the controller and save changes back to the database?
For example what would the following change to once I remove ItemDetailViewModel from the db context?
//
// POST: /Item/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(ItemDetailViewModel itemdetailviewmodel)
{
if (ModelState.IsValid)
{
db.ItemDetailViewModels.Add(itemdetailviewmodel);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(itemdetailviewmodel);
}
Further Details [2]
So am I correct that my Index/Details should work as so or is there a better way of doing it?
//
// GET: /Item/
public ActionResult Index()
{
var items = db.Items.ToList();
var itemdetailviewmodel = AutoMapper.Mapper.Map<ItemDetailViewModel>(items);
return View(itemdetailviewmodel);
}
//
// GET: /Item/Details/5
public ActionResult Details(int id = 0)
{
ItemDetailViewModel itemdetailviewmodel = AutoMapper.Mapper.Map<ItemDetailViewModel>(db.Items.Find(id));
if (itemdetailviewmodel == null)
{
return HttpNotFound();
}
return View(itemdetailviewmodel);
}
Scaffolding is not that intelligent. The standard controller scaffolding template is creating a DbContext with the controller model and presumes you are working with the DB models, not view models and it does not use Automapper. So you'll need to either not use scaffolding, or check what it has done before using it.
And nothing is wrong with the way you use scaffolding, it is just not supposed to do what you expect.
Update this is how you do this without scaffolding
// Without Automapper
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(ItemDetailViewModel model)
{
if (ModelState.IsValid)
{
var item = new Item()
{
Active = model.Active,
ItemCode = model.ItemCode,
Name = model.Name,
ItemOptions = // code to convert from List<ItemDetailItemOptionViewModel> to List<ItemOption>
}
db.Items.Add(item);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(model);
}
// with Automapper - not recommended by author of Automapper
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(ItemDetailViewModel model)
{
if (ModelState.IsValid)
{
var item = Automapper.Mapper.Map<Item>(model);
db.Items.Add(item);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(model);
}
You'll need to modify your DbContext to have IDbSet<Item> Items instead of IDbSet<ItemDetailViewModels> ItemDetailViewModels.
Automapper was created to map from Domain Models to View Models and not the other way. I have done that for a while, but this is troublesome and causes subtle bugs and other maintenance problems. Even Jimmy Bogard himself says you should not map from view models to domain models.

Cannot open generated database from EF Code first

The error I am getting is "Cannot open database "NerdlyDB" requested by the login. The login failed.
Login failed for user 'ComputerName\User Name'.
This is my connection string:
<add name="NerdlyDB" connectionString="Data Source=(LocalDb)\v11.0; Integrated Security=SSPI; initial catalog= NerdlyDB" providerName="System.Data.SqlClient"/>
This database was generates by using EF code first approach. I am new to this one, so I will show you what I did in case it is off somewhere:
On of my Entity Classes:
namespace NerdlyThings.Models
{
public class Post
{
public int ID { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string Content { get; set; }
public DateTime Date { get; set; }
public string Tags { get; set; }
}
}
DBContext Class
namespace NerdlyThings.Models
{
public class NerdlyDB : DbContext
{
public DbSet<Post> Posts { get; set; }
public DbSet<Comment> Comments { get; set; }
public DbSet<Image> Images { get; set; }
public DbSet<Quote> Quotes { get; set; }
}
}
I see that the error is obvious an authentication issue, but I don't know where to set it using code first, only via setting up a db in sql server management studio.
*EDIT***
Ok, so I am not by the computer I originally did this on, but I had some time to kill at work so gave this another go by following the simple instructions here
I did this in Visual Studio 2012 RC in an MVC4 internet application template. Works like a dream and I can only assume I have either some strange configuration issue on my other computer, or something got messed up along the way. Anyway here is what I did:
Classes:
namespace CodeFirstBlog.Models
{
public class Blog
{
public int Id { get; set; }
public string Title { get; set; }
public string BloggerName { get; set; }
public virtual ICollection<Post> Posts { get; set; }
}
public class Post
{
public int Id { get; set; }
public string Title { get; set; }
public DateTime DateCreated { get; set; }
public string Content { get; set; }
public int BlogId { get; set; }
public ICollection<Comment> Comments { get; set; }
}
public class Comment
{
public int Id { get; set; }
public DateTime DateCreated { get; set; }
public string Content { get; set; }
public int PostId { get; set; }
public Post Post { get; set; }
}
}
DBContext Class:
namespace CodeFirstBlog.Models
{
public class BlogContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
public DbSet<Comment> Comments { get; set; }
}
}
I set these up and then created a controller like so (Just had it generated my selecting my context and the class):
public class BlogController : Controller
{
private BlogContext db = new BlogContext();
//
// GET: /Blog/
public ActionResult Index()
{
return View(db.Blogs.ToList());
}
//
// GET: /Blog/Details/5
public ActionResult Details(int id = 0)
{
Blog blog = db.Blogs.Find(id);
if (blog == null)
{
return HttpNotFound();
}
return View(blog);
}
//
// GET: /Blog/Create
public ActionResult Create()
{
return View();
}
//
// POST: /Blog/Create
[HttpPost]
public ActionResult Create(Blog blog)
{
if (ModelState.IsValid)
{
db.Blogs.Add(blog);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(blog);
}
//
// GET: /Blog/Edit/5
public ActionResult Edit(int id = 0)
{
Blog blog = db.Blogs.Find(id);
if (blog == null)
{
return HttpNotFound();
}
return View(blog);
}
//
// POST: /Blog/Edit/5
[HttpPost]
public ActionResult Edit(Blog blog)
{
if (ModelState.IsValid)
{
db.Entry(blog).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(blog);
}
//
// GET: /Blog/Delete/5
public ActionResult Delete(int id = 0)
{
Blog blog = db.Blogs.Find(id);
if (blog == null)
{
return HttpNotFound();
}
return View(blog);
}
//
// POST: /Blog/Delete/5
[HttpPost, ActionName("Delete")]
public ActionResult DeleteConfirmed(int id)
{
Blog blog = db.Blogs.Find(id);
db.Blogs.Remove(blog);
db.SaveChanges();
return RedirectToAction("Index");
}
protected override void Dispose(bool disposing)
{
db.Dispose();
base.Dispose(disposing);
}
}
Then I simply ran the application, used the generated views to create a new Blog. Works great. The database was generated in my App_Data folder, I can access it fine and see the generated schema. So problem solved, maybe? From this point I can use your suggested answers to tweak db settings and whatnot, so thank you.
Are you connecting your DBContext class to that connection string somewhere? My guess is that is missing and therefore causing the problem. I've usually seen the connection string specified in the constructor of the DBContext class (see example below):
public class NerdlyDB : DbContext
{
public NerdlyDB() : base("NerdlyDB")
{
}
...
This will then look for a <connectionString> with name="NerdlyDB" in your web.config / app.config. See this link for more info on setting up EF with your connection string.
I would also recommend using #Eric J.'s approach in your code. You can see a pretty in depth example of his suggestion (and EF code first in general) at silk.codeplex.com (specifically the MileageStats.Data.SqlCe project)
On a separate note, it looks like you are missing the actual code first model setup. Check out the MileageStatsDbContext.cs file in the Silk project to see an example of how to do that.
The best approach I have found so far is to create my own IDatabaseInitializer to run commands that I need to create indices and create users.
public class MyContext : DbContext
{
static private Initializer DbInitializer;
static MyContext()
{
DbInitializer = new MyContext.Initializer();
Database.SetInitializer<MyContext>(DbInitializer);
}
}
public class Initializer : IDatabaseInitializer<MyContext>
{
public void InitializeDatabase(MyContext context)
{
string ddl = "(Some SQL command to e.g. create an index or create a user)";
context.Database.ExecuteSqlCommand(ddl);
}
}

Categories