First I want to say I'm just starting to learn and I'm french, so please be very simple in your explanation. Just imagine you're talking to a 3 years old and I should be ok. Please don't overload me with dozens of lines of code without any explanation.
OK here's what I want to do: I have a very simple database table of article author. The table has 5 columns:
First Name, Second name, Dob, Phone Nb, Place of Birth, UserId
The userId is automatically created. I have created a form where a user would write the first name and second name (in 2 separated textboxes and I want to use that to fetch the userId in the table and use it to delete the entire line)
Here's the code for my form
model projet_clement.Models.HomeModel
<form method="post" action="~/home/SupressionAuteur">
<h3>deleting author page</h3>
<p>first name of the author to delete</p>
<input type="text" name="Nom" />
<p>second name of the author to delete</p>
<input type="text" name="Prenom" /><br />
<br />
<input type="submit" value="Delete" />
</form>
<h3>For reminder, here's a table of the author already created</h3>
<table>
<tr>
<td>Nom</td>
<td>Prenom</td>
<td>Date de naissance</td>
<td>N° de téléphone</td>
<td>Département de naissance</td>
<td>UserId</td>
</tr>
#foreach (var i in Model.UserList)
{
<tr>
<td>#i.Nom</td>
<td>#i.Prenom</td>
<td>#i.Naissance</td>
<td>#i.Numero</td>
<td>#i.Departement</td>
<td>#i.userId</td>
</tr>
}
</table>
OK now what I would like to know is how can I get the userId thanks to the first name and second name, and how can I delete a whole row just using this id.
Here's my c# code
[HttpGet]
public ActionResult SupressionAuteur()
{
var allUsers = db.Users.Where(x => x.Nom != null);
var model = new HomeModel(allUsers);
return View(model);
}
[HttpPost]
public ActionResult SupressionAuteur(Users formUser)
{
//for those who skipped french class, nom = first name and prenom = second name;)
var userId = db.Users.Where(x => x.Nom == formUser.Nom && x.prenom == formuser.prenom);
db.Users.Remove([What should i write here?]);
return RedirectToAction("SupressionAuteur", "Home");
}
Of course it doesn't work!
When I run my code the userId var never get the good value. So I guess the way I try to get it is wrong
And how am I supposed to use the db.users.remove() method? Is it the one I should use by the way? I was told so.
Thanks in advance, I'm really stuck :)
Steps
Get the user - ideally you want to use the userid (or primary key) to retrieve the user
Remove the user from the db
Save the changes in the context
Code:
var user = db.Users.Single(x => x.Nom == formUser.Nom && x.prenom == formuser.prenom);
db.Users.Remove(user);
db.SaveChanges();
Related
In my current MVC project(the third question I've asked on this same project!), I have a 'Landing Page' which after one click of a button redirects to the following page URL:
localhost:111111/AccountsFinance/Index?questionId=1
I can edit the URL manually and change Id=2 which does change what is displayed, but I need a button to do this of course.
Within this View, I have the following:
#using (Html.BeginForm("Index", "AccountsFinance", FormMethod.Post))
{
//SOME CODE
<input class="btn btn-success" type="submit" value="Back" />
<input class="btn btn-success" type="submit" value="Next" />
}
Here is my controller code, not sure if it is necessary for this question but better to include it than not to!
public AccountsFinanceQuestion afqList = new AccountsFinanceQuestion();
public ActionResult Index(string ans)
{
int qId = int.Parse(Request.QueryString["questionId"]);
using (S3WEntities1 ent = new S3WEntities1())
{
afqList.Question = ent.Questions.Where(w => w.QuQuestionId == qId).Select(s => s.QuQuestion).FirstOrDefault().ToString();
afqList.Answers = ent.Answers.Where(w => w.AnsQuestionId == qId).Select(s => s.AnsAnswer).ToList();
}
return View("Index", afqList);
}
So how would I increment/decrement the questionId=X part of the query string so that it moves on to the next question/the previous question. This is all in the same view on the same method on the same controller. I also understand that this may not work so well for the very first question if the user clicks back, as the URL is completely different, but that is something to come on to at a later date.
First of all, you don't need to parse query string parameters manually - default binder will do it for you. Just define method parameter with corresponding name. E.g.
public ActionResult Index(int questionId)
Second, seems like you are reviewing details of some question. So I don't think that Index is appropriate action for that. I suggest to use Details or Edit:
public ActionResult Details(int questionId)
And regarding links to next and previous questions - you can just generate action links in your view:
#Html.ActionLink("Back", "Details", new { questionId = Model.QuQuestionId - 1 }
#Html.ActionLink("Next", "Details", new { questionId = Model.QuQuestionId + 1 })
Also note, that your approach has several problems:
What if some question was deleted and ids are not incremental anymore?
What if current question has id = 1, i.e. it's a first question? It should not have link to previous question
What if current questions is last one?
Easiest way to solve these problems - pass ids of previous and next questions to your view. You can use model properties for that, or you can use ViewBag:
ViewBag.PrevQuestionId = ent.Questions
.Where(q => q.QuQuestionId < questionId)
.OrderByDescending(q => q.QuQuestionId)
.Select(q => q.QuQuestionId)
.FirstOrDefault();
Then in View you can conditionally add link to previous question:
#if (ViewBag.PrevQuestionId > 0) {
#Html.ActionLink("Back", "Details", new { questionId = ViewBag.PrevQuestionId }
}
Same with next question
You can do something like this in your controller:
int qId = int.Parse(Request.QueryString["questionId"]);
Response.RedirectToRoute("current-route?questionId=" + qId++);
In a view I have something like this:
<ul data-role="listview" data-inset="true" data-theme="b" data-split-icon="delete">
#foreach (DataModel.Vulnerability.Fix item in Model.VulnerabilityFixes)
{
<li><a href="#Url.Action("Details", "Product", new { Title = item.Title })">
<h2>#item.Title</h2>
<table style="width: 100%">
<tr>
<th>Id</th>
<th>FixName</th>
<th>Vendor</th>
<th>Version</th>
</tr>
<tr>
<td>#MyHelper.decodeNull(item.Id)</td>
<td>#MyHelper.decodeNull(item.FixName)</td>
<td>#MyHelper.decodeNull(item.Vendor)</td>
<td>#MyHelper.decodeNull(item.Version)</td>
</tr>
</table>
</a>
Delete
</li>
}
</ul>
As you can see it show a table and this table have a delete button that clicked call a DeleteFix() method on an EditingController class and this method take 2 paramethers that are:
vulnId = Model.Id that is a long
the current item that is a DataModel.Vulnerability.Fix object.
So this is the code of my DeleteFix() definied into my EditingController class:
public ActionResult DeleteFix(long vulnId = 0, DataModel.Vulnerability.Fix currentFix)
{
DataModel.Vulnerability.Fix model = new DataModel.Vulnerability.Fix();
manager.openConnection();
try
{
model = currentFix;
}
finally
{
manager.closeConnection();
}
return View(model);
}
The problem is that give me the following error on the signature of this method refered to the second input parameter (the DataModel.Vulnerability.Fix object). It say to me that:
Error 14 Optional parameters must appear after all required
parameters C:\Develop\EarlyWarning\public\Implementazione\Ver2\WebPortal\WebPortal\Controllers\EditingController.cs 27 94 WebPortal
Why? What am I missing? What can I do to pass the previous DataModel.Vulnerability.Fix item object from my view to my DeleteFix() controller method?
Check your function signature:
public ActionResult DeleteFix(long vulnId = 0, DataModel.Vulnerability.Fix currentFix)
Swap the input parameters:
public ActionResult DeleteFix(DataModel.Vulnerability.Fix currentFix, long vulnId = 0)
The error is now gone. The reason is that all parameters that do not get a default value (currentFix) must appear before all parameters that do get a default value (long vulnId = 0)
update
#Neel's answer is also correct, but not related to the error you mentioned.
It's not the cause of the error, but it's also something that needs to be fixed. Assuming this isn't just a typo in the SO question :)
make changes in you actionlink as below and put currentFix instead of fix and change the sequence as below :-
(As flatter suggested )
public ActionResult DeleteFix(DataModel.Vulnerability.Fix currentFix, long vulnId = 0)
and in view
Delete
In C# you cannot declare an optional parameter BEFORE a non optional one.
Change your controller action to be:
public ActionResult DeleteFix(DataModel.Vulnerability.Fix currentFix, long vulnId = 0)
Im playing around with a booking-system in MVC.
I have a view where you select 3 diffrent values (treatment, hairdresser and date).
#using (Html.BeginForm("testing", "Home", FormMethod.Post)) {
<p id="frisor"> Frisör: #Html.DropDownList("Fris", "All")<a class="butt" onclick="showdiv()">Nästa steg</a></p>
<p id="behandling">Behandling: #Html.DropDownList("Cat", "All")<a class="butt" onclick="showdiv2()">Nästa steg</a></p>
<p>
Datum:
<input type="text" id="MyDate" /> <-------This is a jquery datetimepicker
</p
I would like to save the customers three choices in three properties i have created.
My post method looks like this:
[HttpPost]
public ActionResult Testing(string Fris, string Cat, DateTime MyDate)
{
kv.treatment = Cat
kv.Hairdresser = Fris;
kv.Datum = MyDate;
return View();
}
I get the two first (hairdresser,treatment) fine,
the problem is that i dont know how to get the value from the jquery datetimpicker.
Any help appreciated!
The input needs a name in order to be included in the form post:
<input type="text" id="MyDate" name="MyDate" />
Otherwise the browser won't include it in the posted data, so it will never reach the server for model binding. (And, of course, the name has to match the method argument name for the model binder to match them.)
I need to query my database with a WHERE clause and pass to parameters from my view to the controller. I am at a total loss as I am a JavaScript and PHP developer and am currently learning dotnet MVC (I am using vs10 framework4).
I need to in essence make this query:
select * from myTable where column1=16 and column2=24
The values of column1 and column2 are in my View. I have found a million examples on how to pull either a whole table, or a result based upon one parameter, I cannot figure out how to do that simple query.
This seems like a simple task and I would appreciate any help as I have spent 5 hours trying to figure this out.
Here are some key components of my code that will hopefully help someone help me. I sincerely appreciate any help.
Controller:
public class SignBuilderController : Controller
{
SignBuilderModel signBuilderModel = new SignBuilderModel();
//
// Initialize database entities
SignBuilderEntities _db;
public SignBuilderController()
{
_db = new SignBuilderEntities();
}
//
// Get /SignBuilder/PrintSetup
[Authorize]
public ActionResult PrintSetup()
{
var pricesList = signBuilderModel.GetPricingList().ToList();
return View("PrintSetup", pricesList);
}
// get Column1 and column 2 query
public ActionResult TestPage(int column1, int column1)
{
//do something here
return View();
}
And in my View I would retrieve the values for my where clause from input fields.
Example:
<input type="text" name="column1value" id="column1value" />
<input type="text" name="column2value" id="column2value" />
Obviously I am using a Model as well, so if that is needed to make this work no problem. I am really looking for sample code I can use as an example to learn from. I really appreciate any help, and am about to pull out my hair.
Try this(I assume your view is strongly typed):
public ActionResult(int column1, int column2)
{
//do something here.
var model =
(
from p in this.GetPricingList()
where (p.column1 == column1) && (p.column2 == column2)
select p
).FirstOrDefault();
return View(model);
}
and in the View:
<input type="text" name="column1" id="column1value" value="<%=Model.column1%>"/>
<input type="text" name="column2" id="column2value" value="<%=Model.column2%>"/>
You need to post the values to the Action method on your controller
Using something like this in your view:
<% using (Html.BeginForm("RunQuery", "ControllerName")) { %>
<input type="text" name="column1" id="column1value" />
<input type="text" name="column2" id="column2value" />
<input type="submit" value="Run Query" />
<% } %>
and then the accompanying action method
[HttpPost]
public ActionResult RunQuery(string column1, string column2)
{
var results = GetDataFromDatabase(column1, column2);
return View(results );
}
I'm afraid your code would not compile. What you annotated as your controller does not inherit from controller class at all and your actionresult method has no name. I wonder how could you visit your page in the browser. The code should be like
public class MyApplicationModel:Controller
{
//use entity framework
private MyApplicationEntities entities = new MyApplicationEntities();
//
// Method to query database for price lists table
public IQueryable<pricingUploaded> GetPricingList()
{
return entities.pricingUploadeds;
}
//
// Method to query Column1 and Column2 in table pricingUploaded
[HttpGet]
public ActionResult Query()
{
//this action will render the page the first time
return View();
}
[HttpPost]//this method will only accept posted requests
public ActionResult Query(int column1, int column2)
{
//do something here.
var _result = entities.Where(x=>x.column1 == column1 && x.column2 == column2);
return View(_result);//pass result to strongly typed view
}
In your view you have to create a form, that when submitted can post values to HttpPost overload of Query method
<%:Html.BeginForm();%>
<input type="text" name="column1">
<input type="text" name="column2">
<input type="submit" id="save" value="query">
<%:Html.EndForm();%>
Now you enter values in your form and click query button, you will have column1 and column2 values in you Query Actionresult accepting posted request. You better put a break point there and inspect how things are really working and figure out how to do what you need to do.
Edit: based on your comment that you want to pass values ajaxically you can do little bit of jQuery:
<script type="text/javascript">
$(function(){
$("form").submit(function(){
$.ajax({
type:"post",
url:"myapplicationmodel/query",
success:function(data)
{
//do something with returned data
}
});
return false;// to prevent normal form post
});
});
</script>
What about this:
public ActionResult(int column1, int column2)
{
var query = from m in _db.MyTable
where m.Column1 == column1
where m.Column2 == column2
select m;
// Or this for typed model
// select new MyModel { Column1 = m.Column1, etc }
var model = query.First();
return View(model);
}
I'm assuming that the entities is a Linq to Entity right? if that is the case, couldn't you use:
var model = from e in entities
where column1=16 and column2=24
select e;
and then pass that model into the vew.
Basically, if entities is of the type IQueryable or IEnumerable or any of the other linq-able interfaces, you can perform that type of query. Make sure that you are using System.Linq; in the top of your code file.
Hope that helps!
This maybe very simple but I cant seem to sort it out on my own.
I have created a simple db and entity modal that looks like this
I am trying to create an Create form that allows me to add a new Order. I have a total of 3 tables so what I am trying to do is have the form allowing the person to enter Order date and also has a dropdown list that allows me to select a product from the product table
I want to be able to create a Add or Edit view that allow me to insert the OrderDate into the OrderTable and also insert the OrderID and selected ProductID into OrderProduct.
What steps do I need to do here.
I have created an OrderController and ticked the "Add Actions" and than added a Create View which looks like this
#model Test.OrderProduct
#{
ViewBag.Title = "Create2";
}
<h2>Create2</h2>
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>OrderProduct</legend>
<div class="editor-label">
#Html.LabelFor(model => model.OrderID)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.OrderID)
#Html.ValidationMessageFor(model => model.OrderID)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.ProductID)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.ProductID)
#Html.ValidationMessageFor(model => model.ProductID)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
This creates the view that contains a textbox for both OrderID and ProductID however no date.
My controller CreatePost hasnt been changed
[HttpPost]
public ActionResult Create(FormCollection collection)
{
try
{
var data = collection;
// TODO: Add insert logic here
// db.Orders.AddObject(collection);
return RedirectToAction("Index");
}
catch
{
return View();
}
}
My questions are,
1.How do I swap out ProductID textbox to be a dropdown which is populated from Product
2.How do I get the data from FormCollection collection? I thought of just a foreach however I dont know how to get the strongly typed name
Any help for a newbie would be very helpful.
Thank you!
First thing's first, don't bind to the Order entity. Never bind to an EF object, always try and use a ViewModel. Makes life simpler for the View, and that is the goal here.
So, have a ViewModel like this:
public class CreateOrderViewModel
{
public int OrderId { get; set; }
public DateTime OrderDate { get; set; }
public int SelectedProductId { get; set; }
public IEnumerable<SelectListItem> Products { get; set; }
}
That's it right now.
Return that to your View in your [HttpGet] controller action:
[HttpGet]
public ActionResult Create()
{
var model = new CreateOrderViewModel
{
Products = db.Products
.ToList() // this will fire a query, basically SELECT * FROM Products
.Select(x => new SelectListItem
{
Text = x.ProductName,
Value = x.ProductId
});
};
return View(model);
}
Then to render out the list of Products: (basic HTML excluded)
#model WebApplication.Models.CreateOrderViewModel
#Html.DropDownListFor(model => model.SelectedProductId, Model.Products)
The only thing i don't know how to do is bind to the DateTime field. I'm guessing you would need an extension method (HTML Helper) which renders out a Date Picker or something. For this View (creating a new order), just default to DateTime.Now.
Now, onto the [HttpPost] controller action:
[HttpPost]
public ActionResult Create(CreateOrderViewModel model)
{
try
{
// TODO: this manual stitching should be replaced with AutoMapper
var newOrder = new Order
{
OrderDate = DateTime.Now,
OrderProduct = new OrderProduct
{
ProductId = SelectedProductId
}
};
db.Orders.AddObject(newOrder);
return RedirectToAction("Index");
}
catch
{
return View();
}
}
Now, i also think your EF model needs work.
To me (in English terms), a Product can have many orders, and an Order can have many Products.
So, it should be a many-to-many. Currently it's a 1-1 with a redundant join table. Did you generate that from a DB? If so, your DB possibly needs work.
You should have a navigational property called Products on the Order entity, which references a collection of Product, made possible by a silent join to the join table in the many-to-many.
This also means you no longer have a DropDownList, but a MultiSelectDropDownList.
Thanks Craig. Your few days (as at time of posting) of MVC have solved my few days of trying to get the selected value back from DropDownListFor.
I had no problem in the Create view in getting the selected value of the DDLF, but the Edit view was a completely different matter - nothing I tried would get the selected value back in the Post. I noticed the selected value was lurking in the AttemptedValue of the ModelState, and so Dr.Google referred me here.
I had this in my view
#Html.DropDownList(model => model.ContentKeyID, Model.ContentKeys, Model.ContentKeyName)
where ContentKeys is a SelectList populated from the DB via a ViewModel, and ContentKeyName is the curently selected name.
The wierd thing is, I have another DDL on the view populated in an identical manner. This one works. Why, I don't know. It is the second DDL on the form, but I can't see that making a difference.
I read somewhere else it might have been that I was using Guids as the Id, but that didn't seem to make a difference - I changed to Int32, but don't think I had to - I think it's enums that disagree with DDLF. Nullables seemd to make no difference either.
Now that I've added the form collection to my Post ActionResult, and get the selected value using
-view
#Html.DropDownList("ContentKey", Model.ContentKeys)
-in controller (Post)
contentKeyId = int.Parse(form.GetValue("ContentKey").AttemptedValue);
all is good, and I can get on with more exciting things. Why is that the simplest things can hold you up for so long?
I have been struggling with this over the last day or so too. I'll share my limited knowledge in the hope that it will help someone else.
Note that I use a singleton with a pre-populated list to keep my example application small (i.e. no EF or DB interaction).
To show the ProductList you will need to have a ViewBag or ViewData item which contains the ProductList.
You can set this up in the Controller with something like
ViewData["ProductList"] = new SelectList(Models.MVCProduct.Instance.ProductList, "Id", "Name", 1);
Then update your View to something like:
<div class="editor-field">#Html.DropDownList("ProductList")</div>
For the Post/Create/Update step you need to look into the FormCollection to get your results. Reading other posts it sounds like there used to be a bug in here, but it's fixed now so ensure you have the latest. For my example I have a DropDownList for Product so I just get the selected Id and then go searching for that Product in my list.
[HttpPost]
public ActionResult Create(FormCollection form )//Models.MVCOrder newOrder)
{
MVC.Models.MVCOrder ord = Models.MVCOrder.Instance.CreateBlankOrder();
//Update order with simple types (e.g. Quantity)
if (TryUpdateModel<MVC.Models.MVCOrder>(ord, form.ToValueProvider()))
{
ord.Product = Models.MVCProduct.Instance.ProductList.Find(p => p.Id == int.Parse(form.GetValue("ProductList").AttemptedValue));
ord.Attribute = Models.MVCAttribute.Instance.AttributeList.Find(a => a.Id == int.Parse(form.GetValue("attributeId").AttemptedValue));
UpdateModel(ord);
return RedirectToAction("Index");
}
else
{
return View(ord);
}
}
I've only been working on MVC3 for the last few days, so any advice on improving the above would be appreciated.