Deleting relational Non-Content data from Orchard CMS - asp.net-mvc

I have declared some Non-Content data in an Orchard CMS by defining the records and schema like this:
public class CountyRecord
{
public virtual int Id { get; set; }
public virtual string CountyName { get; set; }
public virtual CountryRecord CountryRecord { get; set; }
}
public class CountryRecord
{
public CountryRecord()
{
CountyRecords = new List<CountyRecord>();
}
public virtual int Id { get; set; }
public virtual string CountryName { get; set; }
public virtual IList<CountyRecord> CountyRecords { get; set; }
}
public class Migrations: DataMigrationImpl
{
public int Create()
{
//COUNTIES
SchemaBuilder.CreateTable(typeof(CountyRecord).Name, table => table
.Column<int>("Id", col => col
.PrimaryKey()
.Identity())
.Column<string>("CountyName")
.Column<int>("CountryRecord_Id"));
//COUNTRIES
SchemaBuilder.CreateTable(typeof(CountryRecord).Name, table => table
.Column<int>("Id", col => col
.PrimaryKey()
.Identity())
.Column<string>("CountryName"));
}
}
I then have two controllers handling the admin pages for these two entities. In the country controller I have the following actions:
//DELETE
[HttpGet, Admin]
public ActionResult Delete(int countryId)
{
var country = CountryRepo.Get(countryId);
if (country == null)
{
return new HttpNotFoundResult("Couldn't find the country with ID " + countryId.ToString());
}
return View(country);
}
[HttpPost, Admin, ActionName("Delete")]
public ActionResult DeletePOST(CountryRecord country)
{
foreach (CountyRecord county in CountyRepo.Fetch(c=>c.CountryRecord.Id==country.Id))
{
CountyRepo.Delete(county);
}
CountryRepo.Delete(country);
OrchardServices.Notifier.Add(NotifyType.Information, T("Country '{0}' deleted successfully", country.CountryName));
return RedirectToAction("Index");
}
And this is the view that goes with that:
#model Addresses.Models.CountryRecord
<div class="manage">
#using (Html.BeginFormAntiForgeryPost("Delete"))
{
<h2>Are you sure you want to delete this country and ALL its counties?</h2>
#Html.HiddenFor(m => m.Id);
#Html.HiddenFor(m => m.CountryName);
#Html.ActionLink(T("Cancel").Text, "Index", "CountriesAdmin", new { AreaRegistration = "Addresses" }, new { style = "float:right; padding:4px 15px;" })
<button class="button primaryAction" style="float:right;">#T("Confirm")</button>
}
</div>
However, here's the issue, when I delete a country that still has counties assigned to it, it throws the following error:
a different object with the same identifier value was already associated with the session
Can anyone please help?
Thanks.

It's because your DeletePOST() parameter is a CountryRecord. Orchard records are all proxied by the NHibernate framework and MVC's ModelBinder can't properly create them for you.
What you need to do instead is like what you do in the non-POST method: accept just the integer ID of the CountryRecord, fetch the record fresh from the repository, then delete it.

Related

how to get unique id from radiobuttonfor in mvc

I have a below model
public class category
{
[Key]
public long category_id { get; set; }
public string category_desc { get; set; }
public long? client_id { get; set; }
public long? display_sno { get; set; }
}
controller passing the model to view
public ActionResult category(long? client_id)
{
var category_type = db.category.Where(m => m.client_id == null).ToList();
if(client_id == 10)
{
category_type = db.category.Where(m => m.client_id == client_id).ToList();
}
return View(category_type);
}
In view populating the radion button
#foreach (var item in Model)
{
#Html.DisplayFor(modelItem => item.display_sno)<text>.</text>
#Html.RadioButtonFor(modelItem => item.category_id, item.category_id, new { id=item.category_id})#item.category_desc
}
post Method
public ActionResult Category(category g)
{
}
In post method g is coming as null.
What I am missing here?
Your misunderstanding how radio buttons work. They are for binding one of many options to a single property, in the same way a dropdownlist works. Your code is generating radio buttons that bind to itself. And if you inspect the html you will see that it generates name="item.category_id" which would not bind to your model anyway (that would only bind to a model containing a complex object named Item which contained a property named category_id).
Assuming you have a model for a Product which contained a property for its Category, and you wanted to assign one of the values of your category table to the Category property, then your view models would look like
public class ProductVM
{
[Required(ErrorMessage = "Please select a category")]
public int? Category { get; set; }
public IEnumerable<CategoryVM> CategoryOptions { get; set; }
}
public class CategoryVM
{
public int ID { get; set; }
public string Name { get; set; }
}
Note the use of a nullable property for Category is explained in What does it mean for a property to be [Required] and nullable?
Then the controller methods (for a Create view) would look like
public ActionResult Create()
{
ProductVM model = new ProductVM();
ConfigureViewModel(model);
return View(model);
}
public ActionResult Create(ProductVM model)
{
if (!ModelState.IsValid())
{
ConfigureViewModel(model);
return View(model);
}
.... // Initialize your Product data model, set its properties based on the view model
// Save and redirect
}
private void ConfigureViewModel(ProductVM model)
{
model.CategoryOptions = db.categories.Select(x => new CategoryVM
{
ID = x.category_id,
Name = x.category_desc
});
}
Then the view would be
#model ProductVM
....
#using (Html.BeginForm())
{
#Html.DisplayNameFor(m => m.Category)
foreach(var category in Model.CategoryOptions)
{
<label>
#Html.RadioButtonFor(m => m.Category, category.ID, new { id = "" })
<span>#category.Name</span>
</label>
}
#Html.ValidationMessageFor(m => m.Category)
<input type="submit" .... />
}
Note that the new { id = "" } is removing the id attribute which would otherwise be invalid html because of duplicates.

MVC DropDownListFor getting 2 names

Hi I am developing a banking system for a school assignment. Can you pass 2 Names in a dropdownlist ex:
This is the model
public TransferModel(int bankId, int userid)
{
myAccount = new Service1Client().getAccountByID(bankId);
AccountList = new SelectList(new Service1Client().RetrieveAllAccountsByAccountId(userid), "Id", "Name");
}
I am setting Id, Name to the Select List
View:
<div class="editor-field">
Withdraw From: <%: Html.DropDownListFor(model => model.myAccount.Id, Model.AccountList)%>
</div>
the Select list will only display the name of the accounts. is their by any chance to display the name and the balance in the drop down list.
Thanks
Something like the following would be quite a tidy way of handling this:
public class AccountModel
{
public string Id { get; set; }
public string Name { get; set; }
public Decimal Balance { get; set; }
public string AccountSummary
{
get
{
return String.Format("{0} ({1:C})", Name, Balance);
}
}
}
public class TransferModel
{
public IList<AccountModel> Accounts { get; set; }
public string SelectedAccountId { get; set; }
/* Whatever other properties your view needs */
}
Type your view to TransferModel and do:
<%: Html.DropDownListFor(model => model.SelectedAccountId,
new SelectList { Model.Accounts, "Id", "AccountSummary" )%>

How to read the data from a dropdown in ASP.Net MVC 3

Step 1:
I'm using a dropdown to display company locations. The list comes from the Location table.
Step 2:
While the user is registering, the dropdown list will show the locations in question.
When the user selects India, then this value (Location Name) should store in the UserLogin Table.
How can I read the value from the dropdown in ASP.Net MVC 3?
Create a ViewModel for your form
public class CompanyViewModel
{
public int CompanyId { set;get;}
// Other properties of Company
public int SelectedLocationId { set;get;}
public IEnumerable<Location> Locations { set;get;}
}
Assuming you have a Location class like this
public class Location
{
public int Id { set;get;}
public string Name { set;get;}
}
In the Register (HTTPGET) Action method, Return a CompanyViewModel object with Locations filled from database to the View
public ActionReuslt Register()
{
CompanyViewModel model=new CompanyViewModel();
model.Locations =myRepositary.GetAllLocations();
return View(model);
}
Assuming GetAllLocations returns a list of Location objects from your repositary.
And in the Register View which is strongly typed to CompanyViewModel
#model CompanyViewModel
#using(Html.BeginForm())
{
#Html.DropDownListFor(x=>x.SelectedLocationId,
new SelectList(Model.Locations ,"Id",
"Name"),"Select Location")
<input type="submit" value="Save" />
}
Now write an HTTPPost actionmethod to handle the form post(when user submits the form)
[HttpPost]
public ActionResult Register(CompanyViewModel model)
{
if(ModelState.IsValid)
{
// You will have selected Location id available in model.SelectedLocationId property now
//Save and redirect.
}
//Model Validation failed. so Let us reload the locations again
//because HTTP is stateless and ASP.NET MVC is true to HTTP ! :)
model.Locations =myRepositary.GetAllLocations();
return View(model);
}
Here is some sample code that you can modify and use in your scenario. I don't know what your code looks like so I created my own.
In your view:
#model YourProject.ViewModels.YourViewModel
Your locations dropdown:
<td><b>Location:</b></td>
<td>
#Html.DropDownListFor(
x => x.LocationId,
new SelectList(Model.Locations, "Id", "Name", Model.LocationId),
"-- Select --"
)
#Html.ValidationMessageFor(x => x.LocationId)
</td>
Your view model:
public class YourViewModel
{
// Partial class
public int LocationId { get; set; }
public IEnumerable<Location> Locations { get; set; }
}
Your create action method:
public ActionResult Create()
{
YourViewModel viewModel = new YourViewModel
{
// Get all the locations from the database
Locations = locationService.FindAll().Where(x => x.IsActive)
}
// Return the view model to the view
// Always use a view model for your data
return View(viewModel);
}
[HttpPost]
public ActionResult Create(YourViewModel viewModel)
{
if (!ModelState.IsValid)
{
viewModel.Locations = locationService.FindAll().Where(x => x.IsActive);
return View(viewModel);
}
// If you browse the values of viewModel you will see that LocationId will have the
// value (unique identifier of location) already set. Now that you have this value
// you can do with it whatever you like.
}
Your location class:
public class Location
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsActive { get; set; }
}
This is simple as can come. I hope this helps :)
UPDATE:
My service layer is there for any further business logic and then it calls my repository layer to get the data from the database. I use Entity Framework code first. I also use Autofac for my IoC container.
Your service layer:
public class LocationService : ILocationService
{
private readonly ILocationRepository locationRepository;
public LocationService(ILocationRepository locationRepository)
{
this.locationRepository = locationRepository;
}
public IEnumerable<Location> FindAll()
{
return locationRepository.FindAll();
}
}
And your repository:
public class LocationRepository : ILocationRepository
{
YourDbContext db = new YourDbContext();
public IEnumerable<Location> FindAll()
{
return db.Locations.OrderBy(x => x.Name);
}
}
Your database context class:
public class YourDbContext : DbContext
{
public DbSet<Location> Locations { get; set; }
}
It depends how you are getting values of your form if you are passing formcollection then simply you can access its value by this
public ActionResult MyAction (FormCollection form)
{
string value = form["DropDownListName"];
}
Or you can access it through
string value = Request.Form["DropDownListName"];

MVC Radiobutton binding complex object

I have MVC3 web application where we need to populate radio button list with validation. My Model is something like this:
public class EmployeesViewModel
{
public List<Employee> listEmployee { get; set; } //To persist during post
public IEnumerable<SelectListItem> selectListEmployee { get; set; }
[Required]
public Employee selectedEmployee { get; set; }
}
public class Employee
{
public int ID {get; set;}
public string Name {get; set}
public string Department {get; set}
}
I need to populate radiobutton list something like below:
Employee1ID - Employee1Name - Employee1Department // id - name - department
Employee2ID - Employee2Name - Employee2Department
Employee3ID - Employee3Name - Employee3Department
Selected Employee should be stored into "selectedEmployee" field. What is the best or clean way to populate these radio button List in MVC3?
Note: Mainly Looking for two task:
1. storing "Employee" object in each "Input" radio button tag, so that selected employee will be saved to "selectedEmployee" field
2. Best way to mark "Employee" object as required field
Much appreciate your help!
Thanks,
Here's what I would recommend you. Start with a clean view model, one that really expresses what the view contains as information:
public class EmployeesViewModel
{
public List<EmployeeViewModel> ListEmployee { get; set; }
[Required]
public int? SelectedEmployeeId { get; set; }
}
public class EmployeeViewModel
{
public int ID { get; set; }
public string Label { get; set; }
}
then a controller:
public class HomeController : Controller
{
public ActionResult Index()
{
var model = new EmployeesViewModel
{
ListEmployee = GetEmployees()
};
return View(model);
}
[HttpPost]
public ActionResult Index(EmployeesViewModel model)
{
if (!ModelState.IsValid)
{
// the model is invalid, the user didn't select an employee
// => refetch the employee list from the repository and
// redisplay the view so that he can fix the errors
model.ListEmployee = GetEmployees();
return View(model);
}
// validation passed at this stage
// TODO: model.SelectedEmployeeId will contain the id
// of the selected employee => use your repository to fetch the
// actual employee object and do something with it
// (like grant him the employee of the month prize :-))
return Content("thanks for submitting", "text/plain");
}
// TODO: This doesn't belong here obviously
// it's only for demonstration purposes. In the real
// application you have a repository, use DI, ...
private List<EmployeeViewModel> GetEmployees()
{
return new[]
{
new EmployeeViewModel { ID = 1, Label = "John (HR)" },
new EmployeeViewModel { ID = 2, Label = "Peter (IT)" },
new EmployeeViewModel { ID = 3, Label = "Nathalie (Sales)" },
}.ToList();
}
}
and finally a view:
#model EmployeesViewModel
#using (Html.BeginForm())
{
#Html.ValidationMessageFor(x => x.SelectedEmployeeId)
#foreach (var employee in Model.ListEmployee)
{
<div>
#Html.RadioButtonFor(x => x.SelectedEmployeeId, employee.ID, new { id = "emp" + employee.ID })
#Html.Label("emp" + employee.ID, employee.Label)
</div>
}
<input type="submit" value="OK" />
}

LIstbox in MVC 2

I am having a Employee Table. From that i want to load the Employee Names in a List Box. I dont know from where i should start. Kindly guide me.
As always start by defining the view model that will represent your data:
public class Employee
{
public string Id { get; set; }
public string Name { get; set; }
}
public class MyViewModel
{
public string SelectedEmployeeId { get; set; }
public IEnumerable<Employee> Employees { get; set; }
}
Then the controller which will manipulate the model:
public class HomeController : Controller
{
public ActionResult Index()
{
var model = new MyViewModel
{
// TODO: Instead of hardcoding fetch from your repository
Employees = Enumerable.Range(1, 5).Select(i => new Employee
{
Id = i.ToString(),
Name = "employee " + i
})
};
return View(model);
}
}
And finally generate a dropdown list in the view:
<%: Html.DropDownListFor(
x => x.SelectedEmployeeId,
new SelectList(Model.Employees, "Id", "Name")
) %>
If you want to allow multiple selections a.k.a ListBox a few changes are necessary. First you need an array of employee ids in your model:
public class MyViewModel
{
public string[] SelectedEmployeeIds { get; set; }
public IEnumerable<Employee> Employees { get; set; }
}
And then use the ListBoxFor helper in the view:
<%: Html.ListBoxFor(
x => x.SelectedEmployeeIds,
new SelectList(Model.Employees, "Id", "Name")
) %>
you could also try my AjaxDropdown helper and populate your listbox via jquery Ajax (you don't have to know anything about jquery)
http://awesome.codeplex.com/
there is a live demo that you can try and download

Resources