A concise way to handle multiple checkboxes for a model - c#

I have two classes, Songs and Tags.The relationship is many-to-many. The problem I'm having is that when a user adds a new Song and checks off what Tags s/he wants and I call db.SaveChanges() in the controller, it adds duplicate Tags instead of adding only records to the join table. I've worked around this, but it's a hack. There's got to be a better solution?
Here's my code (abrreviated for clarity).
Song:
public int Id { get; set; }
public List<Tag> Tags { get; set; }
public string SongTitle { get; set; }
Tag:
public int Id { get; set; }
public string TagName { get; set; }
public bool Selected { get; set; }
public List<Song> Songs { get; set; }
Controller:
public ActionResult Create()
{
Song song = new Song();
song.Tags = utilities.TagNames(_db, User.Identity.Name);
return View(song);
}
[HttpPost]
public ActionResult Create(Song song)
{
//cycle thru the tags and grab ids of checked tags
int tagCount = song.Tags.Count;
List<int> tagIds = new List<int>();
for (int i = tagCount - 1; i > -1; i--)
{
Tag tag = song.Tags[i];
if (tag.Selected)
tagIds.Add(tag.Id);
}
song.Tags = null;
if (ModelState.IsValid)
{
_db.Songs.Add(song);
_db.SaveChanges();
int songId = song.Id;
string sql = "INSERT INTO [dbo].[TagSongs] (Tag_Id, Song_Id) VALUES ";
foreach(int tagid in tagIds)
{
sql += "(" + tagid + "," + songId + "),";
}
//remove the last comma
sql = sql.Substring(0, sql.Length - 1);
_db.Database.ExecuteSqlCommand(sql);
return RedirectToAction("Index");
}
SetCategoriesAndTags(song);
return View(song);
}
View:
#for (int i = 0; i < Model.Tags.Count; i++)
{
Tag t = Model.Tags[i];
#Html.CheckBoxFor(m => m.Tags[i].Selected)
<label for="Tags_#i.ToString()__Selected">#t.TagName</label>
#Html.HiddenFor(m => m.Tags[i].Id)
#Html.HiddenFor(m => m.Tags[i].TagName)
}

First off, do not use string concatenation for SQL queries or this will open you up to SQL Injection attack. This code should get you what you need. Call it from your controller ActionMethod.
private void AddSongs(Song song, List<int> tagIds)
{
_db.Songs.Add(song);
foreach(var tagId in tagIds)
{
var tag = _db.Tags.SingleOrDefault(tagId);
if(tag != null) song.Tags.Add(tag);
}
_db.SaveChanges();
}

Related

I need to create List<a> include List<t> with in it. Anyone can help for this

I have a set of data that have duplication because of joining to another table. I need to remove the duplicate and add to another List and each of that element include a list of some element.
As example :
I need to insert this data to the list: List<ExistingQuestionDTO> existingQuestions = new List<ExistingQuestionDTO>();
public class ExistingQuestionDTO
{
public int Id { get; set; }
public int QuestionId { get; set; }
public string QuestionTitle { get; set; }
public string SurveyTitle { get; set; }
public int SurveyId { get; set; }
public string OptionType { get; set; }
public IEnumerable<Tag> Tags { get; set; }
}
I took this data to below List:IEnumerable<ExistingQuestionSpResult> existingQuestionSpResults
and try to make an list using below algorithm. But it wont give an expected result.
private IEnumerable<ExistingQuestionDTO> MakeExistingQuestionSearchableDTO(
IEnumerable<ExistingQuestionSpResult> existingQuestionSpResults)
{
int previousQuestionId = 0;
List<Tag> exitingTags = new List<Tag>();
List<Tag> newTags = new List<Tag>();
List<ExistingQuestionDTO> existingQuestions = new List<ExistingQuestionDTO>();
ExistingQuestionDTO previousExistingQuestionDTO = new ExistingQuestionDTO();
foreach (var questionSpResult in existingQuestionSpResults)
{
if (questionSpResult.QuestionId == previousQuestionId ||
previousQuestionId == 0)
{
//Adding new tag if questionId exist for existing tag
if (!(newTags.Count == 0))
{
exitingTags.AddRange(newTags);
//Clear newTags array here...
newTags.Clear();
}
//Add Tags for same array.
if (!(questionSpResult.ColumnName == "NULL"))
{
Tag tag = new Tag
{
TagId = (Guid)questionSpResult.TagId,
TagName = questionSpResult.ColumnName
};
exitingTags.Add(tag);
}
}
else
{
//Add Tags for new array with Other Items too...
exitingTags.Clear();
newTags.Clear();
if (!(questionSpResult.ColumnName == "NULL"))
{
Tag tag = new Tag
{
TagId = (Guid)questionSpResult.TagId,
TagName = questionSpResult.ColumnName
};
newTags.Add(tag);
}
}
ExistingQuestionDTO existingQuestionDTO = new ExistingQuestionDTO
{
Id = questionSpResult.Id,
QuestionId = questionSpResult.QuestionId,
QuestionTitle = questionSpResult.QuestionTitle,
SurveyId = questionSpResult.SurveyId,
SurveyTitle = questionSpResult.SurveyTitle,
OptionType = questionSpResult.OptionType,
Tags = exitingTags.Count != 0 ? exitingTags : newTags
};
if (questionSpResult.QuestionId == previousQuestionId)
{
//Update Tag in relevant node...
//existingQuestions.RemoveAt((int)questionSpResult.QuestionId - 1);
//existingQuestions.Remove(previousExistingQuestionDTO);
//existingQuestions.Add(existingQuestionDTO);
//existingQuestions.Insert(((int)questionSpResult.QuestionId - 1),
// existingQuestionDTO);
var foundQuestion = existingQuestions.Find(a =>
a.QuestionId == questionSpResult.QuestionId);
foundQuestion.Tags = exitingTags;
existingQuestions[(int)questionSpResult.QuestionId - 1] = foundQuestion;
}
else
{
existingQuestions.Add(existingQuestionDTO);
}
previousQuestionId = questionSpResult.QuestionId;
previousExistingQuestionDTO = existingQuestionDTO;
}
IEnumerable<ExistingQuestionDTO> exitingQuestionList = existingQuestions;
return exitingQuestionList;
}
Can somebody show me what went wrong here ?
QuestionId 3 should have Tags.count => 2. But for here it gives 17. I am so confused.
Since redundancy reason is not mentioned properly and row-wise its completely unique except for questionid 3 where the status has both critical and important. So, first, you have to add a filter for the same and see if you are getting completely unique results or not.

LinQ to SQL missing data

I'm trying to get all rows from my SANPHAM table but somehow it keeps missing some rows. The table has 9 rows, however, when displayed, it show only 5 rows (I have picture below, and don't mind about products' image, I will add the rests later).
I have tried to do something in my code, I change int i = 0 to int i = 1 and there are 2 situations. With i = 0, the result misses even rows and with i = 1, odd rows disappear.
I am a newbie to this, I looked for some solutions but still can't fix it, hope you guys can help
Here is my code:
HomeControllers.cs:
namespace MvcApplication.Controllers
{
public class HomeController : Controller
{
private LinQtoSQLDataContext LinQtoSQLDataContext = new LinQtoSQLDataContext();
public ActionResult Index()
{
IList<Models.SanPhamModels> sanPhamList = new List<Models.SanPhamModels>();
var query = from sanpham in LinQtoSQLDataContext.SANPHAMs select sanpham;
var sps = query.ToList();
foreach (var sanPhamData in sps)
{
sanPhamList.Add(new Models.SanPhamModels()
{
maSanPham = sanPhamData.maSanPham,
tenSanPham = sanPhamData.tenSanPham,
gia = sanPhamData.gia,
tacGia = sanPhamData.tacGia,
moTa = sanPhamData.moTa,
maDanhMuc = sanPhamData.maDanhMuc,
hinhAnh = sanPhamData.hinhAnh
});
}
return View(sanPhamList);
}
public ActionResult About()
{
ViewBag.Message = "Your app description page.";
return View();
}
public ActionResult Contact()
{
ViewBag.Message = "Your contact page.";
return View();
}
}
}
Index.cshtml:
#for (int i=0; i<Model.Count; i++)
{
var tmp = "<div class=\"product_box\">";
tmp += "<img src=\""+ Url.Content(Model[i].hinhAnh) + "\" alt=\"Image\" /><br>";
tmp += Html.ActionLink(Model[i].tenSanPham, "productdetail", new { maSanPham = Model[i].maSanPham }, null);
tmp += "<p class=\'product_price\">" + Model[i].gia.ToString() + "</p>";
tmp += Html.ActionLink("Add to Cart", "shoppingcart", new { maSanPham = Model[i].maSanPham }, new {#class = "add_to_card"});
tmp += Html.ActionLink("Detail", "productdetail", new { maSanPham = Model[i].maSanPham }, new { #class = "detail" });
tmp += "</div>";
#Html.Raw(tmp)
}
SanPhamModels:
namespace MvcApplication.Models
{
public class SanPhamModels
{
public string maSanPham { get; set; }
public string tenSanPham { get; set; }
public double gia { get; set; }
public string tacGia { get; set; }
public string moTa { get; set; }
public string maDanhMuc { get; set; }
public string hinhAnh { get; set; }
}
}
My database
My website result image
EDITED:
I see what problem with my project:
Problem
a <div> inside a <div> so that it shows only the odd rows or even rows. Now I am working on this issue, still need some help...
you have to define the model in top with list as you are returning the list from controller.
#model IEnumerable<Models.SanPhamModels>

How to write Users checkbox checks into multiple records in database - using MVC, C#, Razor, nHibernate

So im trying to insert into my database the values from check boxes that the user checked.
In my ViewModel:
[Display(Name = "Title")]
public string Title { get; set; }
public IEnumerable<SelectListItem> UserTitlelist { get; set; }
public IEnumerable<SelectListItem> Titles { get; set; }
In my View:
#foreach (var item in Model.Titles)
{
<label class="managelabel" style="padding: 0 5px 0 5px;"><input name="Title" type="checkbox" value="#item.Value" #checkedcheckbox> #item.Text</label>
}
In my Controller:
var titleToInsert = new UserTitle
{
UserId = currentUserId,
TitleId = model.Title[];
};
UserManagerService.UpdateUserTitles(titleToInsert);
In UserManagerService:
public static int UpdateUserTitles(UserTitle userTitle)
{
using (ITransaction transaction = Context.BeginTransaction())
{
foreach (var x in userTitle)
{
Context.Save(userTitle);
}
transaction.Commit();
}
return 0;
}
You view model is incorrect and has no relationship at all to what you are editing. And SelectListItem is a class for use in #Html.DropDownListFor(), not for a collection of checkboxes.
You view models should be
public class TitleVM
{
public int ID { get; set; }
public string Name { get; set; }
public bool IsSelected { get; set; }
}
public class UserTitleVM
{
.... // other properties
public List<TitleVM> Titles { get; set; }
}
And in the view
#model UserTitleVM
#using (Html.BeginForm())
{
....
for(int i = 0; i < Model.Titles.Count; i++)
{
#Html.HiddenFor(m => m.Titles[i].ID)
#Html.CheckBoxFor(m =>m.Titles[i].IsSelected)
#Html.LabelFor(m => m.Titles[i].IsSelected, Model.Titles[i].Name)
}
and in the controller
public ActionResult Edit(UserTitleVM model)
{
// Get the ID's of the selected titles
List<int> selectedTitles = model.Titles.Where(t => t.IsSelected).Select(t => t.ID);
....
I found the answer is quite simple:
in the controller:
var myList = Request.Form["Title"];
foreach (var item in myList.Split(','))
{
var titleToInsert = new UserTitle
{
UserId = currentUserId,
TitleId = Convert.ToInt32(item)
};
UserManagerService.UpdateUserTitles(titleToInsert);
}
then in UserManagerService:
public static int UpdateUserTitles(UserTitle userTitle)
{
using (ITransaction transaction = Context.BeginTransaction())
{
Context.Save(userTitle);
transaction.Commit();
}
return 0;
}
This way each record gets saved individually

How do I keep this scenario to 1 round trip?

I have a page that is a list of users. The controller's Index function is the action responsible for showing the page of users. The user can select those users and chose to delete them.
I perform the delete action with an ajax request, however then the page's list of users is out of date. So I reload the page because I want to re-use the index action, and all the query string parameters are still there. This means I'm performing two round trips. How do I avoid this?
function DeleteUsers()
{
var selectedUserIds = ;
$.post("/Account/DeleteUsers",
{
userIds: selectedUserIds
},
function (data) {
if( data.status == "success"){
location.reload();
}
});
}
Index function:
[AuthorizeActionFilter]
public ActionResult Index(UserModel model)
{
ViewData["PageTitle"] = ServiceSite.Resources.Resources.REGISTERED_USERS;
ViewBag.MaxUsersPerPage = PAGE_MAX_COUNT;
if(model == null)
{
model = new UserModel();
}
int totalCount = 0;
//Get users
model.Users = CADC.GetUsers(AccountController.GetRegionID(), model.CompanyID, out totalCount,
model.SortField, model.PageNumber * PAGE_MAX_COUNT, PAGE_MAX_COUNT, model.Ascending, User.Identity.Name);
model.TotalUserCount = totalCount;
int totalPages = totalCount / PAGE_MAX_COUNT;
model.TotalPages = (totalCount % PAGE_MAX_COUNT) == 0 ? totalPages : totalPages + 1;
return View(model);
}
and the model:
public class UserModel
{
public bool Ascending { get; set; }
public int PageNumber { get; set; }
public string SortField { get; set; }
public int TotalUserCount { get; set; }
public int TotalPages { get; set; }
public long CompanyID { get; set; }
public List<User> Users { get; set; }
public UserModel()
{
this.Ascending = true;
this.PageNumber = 0;
this.SortField = "FirstName";
this.CompanyID = 0;
this.TotalUserCount = 0;
this.TotalPages = 0;
}
}
I agree with #David's comments. In the AJAX success block, remove the rows just deleted based on what you requested to delete.
The pagination is indeed more complicated; either adjust it in the same way, or revamp everything to use a proper view model in Javascript with bound elements--see AngularJS or other such frameworks.

How to update a List in C#

IList<ReceiptAllocationMaster> objReceiptMaster = (IList<ReceiptAllocationMaster>)Session["AllocationResult"];
public class ReceiptAllocationMaster
{
public string application { get; set; }
public List<Users> users { get; set; }
}
public class Users
{
public string name { get; set; }
public string surname { get; set; }
}
I need to Update the above list with some value where application = "applicationame" and users where surname = "surname" into the same list.
Just iterate over your list and modify matched items:
for (int i = 0; i < objReceiptMaster.Count; i++)
{
var item = objReceiptMaster[i];
if (item.application == "applicationname" && item.users.Any(x => x.surname == "surname"))
objReceiptMaster[i] = new ReceiptAllocationMaster();
}
Instead of new ReceiptAllocationMaster() you can write any modification data logic.
though your question is not clear, this shd give u some idea:
objReceiptMaster.Where(x=>x.application=="applicationname" &&
x.users.Any(d=>d.surname=="surname"))
.ToList()
.ForEach(item=>{//update your list
item.application = "whatever value";
item.users.ForEach(user=>{//update users
user.name="whatever username";
});
});

Categories

Resources