What we want to achieve?
Step 1 : In controller we have action methods to update products, its features, delete product and delete its feature.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using SampleMvc.Helpers;
using SampleMvc.Models;
using SampleMvc.DA;
using Newtonsoft.Json;
using System.IO;
namespace SampleMvc.Controllers
{
public class ManageProductController : Controller
{
public ActionResult Products()
{
ListProductCategoryAndFeature listProductCategoryAndFeature = new ListProductCategoryAndFeature();
List<Product> product = new List<Product>();
List<ProductFeature> productfeatures = new List<ProductFeature>();
ProductDA productDA = new ProductDA();
product = productDA.ReadAllProducts();
listProductCategoryAndFeature = productDA.ReadAllProductFeaturesAndCategory();
ViewBag.ProductFeatures = listProductCategoryAndFeature.productfeatures;
ViewBag.ProductCategories = listProductCategoryAndFeature.productcategories;
return View(product);
}
[HttpPost]
public ActionResult Products(string product)
{
var listProducts = JsonConvert.DeserializeObject<List<Product>>(product);
foreach (var prod in listProducts)
{
ProductDA productDA = new ProductDA();
productDA.UpdateProductAndFeatures(prod);
}
return Json(new { Success = true });
}
public ActionResult UpdateImage()
{
string imgName = string.Empty;
ProductDA productDA = new ProductDA();
if (System.Web.HttpContext.Current.Request.Files.AllKeys.Any())
{
for (int i = 0; i < System.Web.HttpContext.Current.Request.Files.Count; i++)
{
var pic = System.Web.HttpContext.Current.Request.Files[i];
var pid = System.Web.HttpContext.Current.Request.Form[i];
if (pic.ContentLength > 0)
{
var fileName = Path.GetFileName(pic.FileName);
var ext = Path.GetExtension(pic.FileName);
if (ext == ".jpg" || ext == ".png" || ext == ".jpeg" || ext == ".gif")
{
string imgPath = "";
imgPath = "/ProductImages/" + pid + ext;
Product prod = new Product();
prod.ProductId = Convert.ToInt32(pid);
prod.ImagePath = imgPath;
productDA.UpdateProductImage(prod);
// TODO : Crop Image before saving
string path = Server.MapPath(imgPath);
pic.SaveAs(path);
}
}
}
}
return Json(new { Success = true });
}
[HttpPost]
public ActionResult DeleteProduct(Product product)
{
ProductDA productDA = new ProductDA();
productDA.DeleteProduct(product);
return Json(new { Success = true });
}
[HttpPost]
public ActionResult DeleteProductFeature(int fid)
{
ProductDA productDA = new ProductDA();
productDA.DeleteProductFeature(fid);
return Json(new { Success = true });
}
}
}
Step 2 : In Views :
@{
ViewBag.Title = "Manage Product";
Layout = "~/Views/Shared/_Layout.cshtml";
}
@model List<SampleMvc.Models.Product>
@using SampleMvc.Models;
<div class="container-fluid">
<div class="row content">
<div class="col-sm-3 sidenav">
<h4>Manage Products</h4>
<ul class="nav nav-pills nav-stacked">
<li class="active"><a href="#section1">Home</a></li>
<li><a href="/Product/Product">Bulk Product Upload</a></li>
<li><a href="/ManageProduct/Products">Manage Products</a></li>
<li><a href="#section3">Photos</a></li>
</ul>
<br>
<div class="input-group">
<input type="text" class="form-control" placeholder="Search Blog..">
<span class="input-group-btn">
<button class="btn btn-default" type="button">
<span class="glyphicon glyphicon-search"></span>
</button>
</span>
</div>
</div>
<div class="col-sm-9">
<h4><small>Manage Products and its features.</small></h4>
<hr>
<div class="col-sm-12">
@foreach (var product in Model)
{
<div id="@string.Format("product{0}", product.ProductId)" class="manageProduct" pid="@product.ProductId">
<div class="row">
<div class="col-sm-3">
@(Model.IndexOf(product) + 1) )
Product Name :
</div>
<div class="col-sm-6">
<input type="text" class="form-control" id="@string.Format("txtProductName{0}", product.ProductId)" value="@product.ProductName" />
<div id="@string.Format("errProductName{0}", product.ProductId)" class="divErr"></div>
</div>
<div class="col-sm-3">
<a href="javascript:;" class ="btn btn-danger delProduct" title="Delete Product" pid="@product.ProductId">Delete</a>
</div>
</div>
<br />
<div class="row">
<div class="col-sm-3">
Product Features :
</div>
<div class="col-sm-6">
<ul class="list-group" id="@string.Format("choiceList{0}", product.ProductId)">
@foreach (var feature in (List<ProductFeature>)ViewBag.ProductFeatures)
{
if (feature.ProductId == product.ProductId)
{
<li class="list-group-item list-group-item-info" id="@string.Format("li{0}", feature.FeatureId)">
<div class="divOption fwidth">
<div class="divAnsOption hwidth">
<label class="rdAnsOption" type="text" name="choice" fid="@feature.FeatureId" value="@feature.ProdFeature" /> @feature.ProdFeature
</div>
<div class="divOrderBy">
<input type="text" class="rdAnsOrder form-control" value="@feature.OrderBy" style="width:44px"/>
</div>
<div class="divRemoveOpt"><a href="javascript:;" class="delChoice" fid="@feature.FeatureId" title="Remove Choice">X</a></div>
</div>
</li>
}
}
</ul>
<input type="button" id="@string.Format("btnAddFeature{0}", @product.ProductId)" class="btn btn-primary" value="Add Feature"/>
<div class="divAddOption" id="@string.Format("divAddOpt{0}", @product.ProductId)">
Enter Feature :
<input id="@string.Format("txtFeature{0}", @product.ProductId)" type="text" class="form-control" required="required" />
<div id="@string.Format("errFeature{0}", @product.ProductId)" class="divErr"></div><br />
<input type="button" id="@string.Format("btnAddOpt", @product.ProductId)" class="btn btn-primary" value="Add" />
</div>
</div>
<div class="col-sm-3">
</div>
</div>
<br />
<div class="row">
<div class="col-sm-3">
Product Category :
</div>
<div class="col-sm-6">
<select id="@string.Format("drpProductCategory{0}", product.ProductId)" class="form-control">
<option value="0">Select Category</option>
@foreach (var m in @ViewBag.ProductCategories)
{
if (m.CategoryId == product.CategoryId)
{
<option value= "@m.CategoryId" selected>@m.CategoryName </option>
}
else
{
<option value= "@m.CategoryId">@m.CategoryName </option>
}
}
</select>
<div id="@string.Format("errProductCategory{0}", product.ProductId)" class="divErr"></div>
</div>
<div class="col-sm-3">
</div>
</div>
<br />
<div class="row">
<div class="col-sm-3">
Quantity Per Unit :
</div>
<div class="col-sm-6">
<input type="text" class="form-control" id="@string.Format("txtQuantityPerUnit{0}", product.ProductId)" value="@Convert.ToInt32(product.QuantityPerUnit)" />
</div>
<div class="col-sm-3">
</div>
</div>
<br />
<div class="row">
<div class="col-sm-3">
Unit Price :
</div>
<div class="col-sm-6">
<input type="text" class="form-control" id="@string.Format("txtUnitPrice{0}", product.ProductId)" value="@Convert.ToInt32(product.UnitPrice)" />
</div>
<div class="col-sm-3">
</div>
</div>
<br />
<div class="row">
<div class="col-sm-3">
Product Image :
</div>
<div class="col-sm-6">
<input type="file" name="postedFile" id="@string.Format("imgProductImageUrl{0}", product.ProductId)" />
</div>
<div class="col-sm-3">
<img src="@Url.Content((string.IsNullOrEmpty(product.ImagePath) == true ? "/Images/noimage.png" : product.ImagePath))" alt="@product.ProductName" width="150px" />
</div>
</div>
<br />
</div>
}
<input type="button" value="Save" id="btnSaveProduct" class="btn btn-primary" />
</div>
</div>
</div>
</div>
@section scripts {
<script src="~/Scripts/ManageProducts.js"></script>
}
Step 3 : In Javascript File ManageProducts.js :
var productManage = {
init: function () {
$(".manageProduct").each(function () {
var id = $(this).attr("pid");
var divQues = '#ques' + id;
$("#choiceList" + id).sortable({
stop: function (event, ui) {
var sort = $('#choiceList' + id).find('input[type="text"]');
sort.each(function (index) {
$(this).val((index + 1));
});
}
});
$("#btnAddFeature" + id).click(function () {
$("#divAddOpt" + id).show();
$("#btnAddFeature" + id).hide();
});
$("#txtBaseValue" + id).keypress(function (event) {
$("#errBaseValue" + id).html("");
var key = event.which;
if (!(key >= 48 && key <= 57)) {
event.preventDefault();
$("#errBaseValue" + id).html("Only numeric value is allow.");
}
});
// Add choice
var addChoice = function (input) {
var val = $.trim($(input).val());
$("#choiceList" + id).append('<li class="list-group-item list-group-item-info" id="li' + id + '"><div class="divOption fwidth"><div class="divAnsOption hwidth"><label class="rdAnsOption" type="text" name="choice" fid="0" value="' + val + '" t="N" >' + val + '</label></div><div class="divOrderBy"><input type="text" class="rdAnsOrder form-control" style="width:44px" value="' + ($("#choiceList" + id + " li").length + 1) + '"/></div><div class="divRemoveOpt"><a href="javascript:;" class="delChoice" title="Remove Choice">X</a></div></div></li>');
$(input).val("");
$(".delChoice").click(function () {
var fid = $(this).attr("fid");
if (!fid) {
$(this).parent().parent().parent().remove();
productManage.sortOptions(id);
}
});
};
$(".delChoice").click(function () {
var fid = $(this).attr("fid");
if ($("#dialogdelete")) $("#dialogdelete").remove();
$("body").append("<div id='dialogdelete'>Do you want to delete this feature?</div>");
$("#dialogdelete").dialog({
modal: true,
title: 'Delete Feature',
width: 400,
buttons: {
Delete: function () {
alert(fid);
$(this).dialog("close");
$.ajax({
data: { fid: fid },
type: "POST",
url: "/ManageProduct/DeleteProductFeature",
success: function (data) {
if (data.Success) {
$("#li" + fid).remove();
productManage.sortOptions(id);
}
}
});
},
Cancel: function () {
$(this).dialog("close");
}
}
});
});
$("#txtFeature" + id).change(function () {
$("#errFeature" + id).html("");
if ($("#choiceList" + id + " li").length == 0) {
addChoice(this);
}
else {
var count = 0;
$("#choiceList" + id + " label").each(function (i) {
var addFeature = $.trim($(this).text());
if ($.trim($("#txtFeature" + id).val()).toLowerCase() == addFeature.toLowerCase()) {
count = count + 1;
}
else {
}
});
if (count == 0) {
addChoice($("#txtFeature" + id));
}
else {
$("#errFeature" + id).html("Feature already added.");
$("#txtFeature" + id).focus();
}
}
});
// This section has not been implemented here.
$("#drpFeatureType" + id).change(function () {
if ($("#drpFeatureType" + id + " option:selected").text() == "Text") {
if ($("#dialogdelete")) $("#dialogdelete").remove();
$("body").append("<div id='dialogdelete'>Do you want to delete all Feature?</div>");
$("#dialogdelete").dialog({
modal: true,
title: 'Delete All Feature',
width: 400,
buttons: {
Delete: function () {
$(this).dialog("close");
$.ajax({
data: { pid: id },
type: "POST",
url: "/ManageProduct/DeleteAllFeature",
success: function (data) {
if (data.Success) {
$("#choiceList" + id).empty();
$("#btnAddFeature" + id).hide();
productManage.sortOptions(id);
}
}
});
},
Cancel: function () {
$(this).dialog("close");
$("#drpQuestionType" + id).val("R");
}
}
});
}
else {
$("#btnAddFeature" + id).show();
}
});
});
},
validateProduct: function () {
var counterr = 0;
$(".manageProduct").each(function () {
counterr = 0;
var id = $(this).attr("pid");
$('span[id^="spnMsg"]').html("");
$('div[id^="err"]').html("");
if ($("#txtProductName" + id).val() == "") {
$("#txtProductName" + id).focus();
$("#errProductName" + id).html("Please enter Product Name.");
counterr++;
return false;
}
else if ($("#drpProductCategory" + id + " option:selected").val() == 0) {
$("#drpProductCategory" + id).focus();
$("#errProductCategory" + id).html("Please select Product Category.");
counterr++;
return false;
}
});
if (counterr > 0)
return false;
else
return true;
},
sortOptions: function (id) {
var sort = $('#choiceList' + id).find('input[type="text"]');
sort.each(function (index) {
$(this).val((index + 1));
});
}
};
$("#btnSaveProduct").click(function () {
if (productManage.validateProduct()) {
jsonProductObj = [];
var data = new FormData();
$(".manageProduct").each(function () {
var id = $(this).attr("pid");
product = {}
product["ProductId"] = id;
product["ProductName"] = $("#txtProductName" + id).val();
product["CategoryId"] = $("#drpProductCategory" + id + " option:selected").val();
product["QuantityPerUnit"] = $("#txtQuantityPerUnit" + id).val();
product["UnitPrice"] = $("#txtUnitPrice" + id).val();
//product["Discounted"] = $("#txtDiscount" + id).is(":checked");
var count = 0;
var ProductFeature = "";
$('#choiceList' + id + ' label').each(function (index) {
ProductFeature = ProductFeature + $(this).attr('fid') + "+|+" + $(this).attr('value') + "+|+" + $(this).is(':checked') + "+|+" + $(this).parent().parent().find('input:text').val() + "*|*";
if ($(this).is(':checked'))
count = count + 1;
});
product["ProductFeature"] = ProductFeature;
jsonProductObj.push(product);
// Adding images to formdata
var files = $("#imgProductImageUrl" + id).get(0).files;
if (files.length > 0) {
data.append("MyImages" + id, files[0]);
data.append("Pid" + id, id);
}
});
$.ajax({
type: 'post',
dataType: 'json',
url: '/ManageProduct/Products',
data: { "product": JSON.stringify(jsonProductObj) },
success: function (json) {
$.ajax({
url: "/ManageProduct/UpdateImage",
type: "POST",
processData: false,
contentType: false,
data: data,
success: function (response) {
window.location.href = '/ManageProduct/Products';
}
});
},
});
}
});
$(".delProduct").click(function () {
var product = {};
product.ProductId = $(this).attr("pid");
if ($("#dialogdelete")) $("#dialogdelete").remove();
$("body").append("<div id='dialogdelete'>Do you want to delete this Product?</div>");
$("#dialogdelete").dialog({
modal: true,
title: 'Delete Product',
width: 400,
buttons: {
Delete: function () {
$(this).dialog("close");
alert(product.ProductId);
$.ajax({
url: '/ManageProduct/DeleteProduct',
method: 'post',
data: '{product: ' + JSON.stringify(product) + '}',
contentType: "application/json; charset=utf-8",
success: function () {
window.location.reload(true);
},
error: function (err) {
}
});
},
Cancel: function () {
$(this).dialog("close");
}
}
});
});
$(document).ready(function () {
productManage.init();
});
Step 4 : In DataAccess Class Library :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SampleMvc.Models;
using System.Data.SqlClient;
namespace SampleMvc.DA
{
public class ProductDA : SQLHelper
{
public void AddProductAndFeatures(Product product, string productFeature)
{
try
{
int i = ExecNonQueryProc("Usp_InsertProductAndFeatures",
new SqlParameter("@ProductName", product.ProductName),
new SqlParameter("@CategoryId", product.CategoryId),
new SqlParameter("@ProductFeatures", productFeature));
}
catch
{
throw;
}
finally
{
CloseConnection();
}
}
public List<Product> ReadAllProducts()
{
List<Product> products = new List<Product>();
SqlDataReader rdr = ExecDataReaderProc("Sp_ReadAllProducts");
while (rdr.Read())
{
Product product = new Product();
product.ProductId = Convert.ToInt32(rdr["ProductId"]);
product.ProductName = Convert.ToString(rdr["ProductName"]);
product.CategoryId = Convert.ToInt32(rdr["CategoryId"]);
//product.QuantityPerUnit = Convert.ToInt32(rdr["QuantityPerUnit"]);
//product.UnitPrice = Convert.ToInt32(rdr["UnitPrice"]);
product.ImagePath = Convert.ToString(rdr["ImagePath"]);
//product.UnitsInStock = Convert.ToInt32(rdr["UnitsInStock"]);
//product.Discounted = Convert.ToBoolean(rdr["Discounted"]);
//product.CreateOn = Convert.ToDateTime(rdr["CreateOn"]);
products.Add(product);
}
CloseConnection();
return products;
}
// Returning multiple result set from procedure.
public ListProductCategoryAndFeature ReadAllProductFeaturesAndCategory()
{
ListProductCategoryAndFeature listProductCategoryAndFeature = new ListProductCategoryAndFeature();
List<ProductFeature> productfeatures = new List<ProductFeature>();
List<ProductCategory> productcategories = new List<ProductCategory>();
SqlDataReader rdr = ExecDataReaderProc("Sp_ReadAllProductFeatures");
while (rdr.Read())
{
ProductFeature productfeature = new ProductFeature();
productfeature.ProductId = Convert.ToInt32(rdr["ProductId"]);
productfeature.ProdFeature = Convert.ToString(rdr["ProductFeature"]);
productfeature.FeatureId = Convert.ToInt32(rdr["FeatureId"]);
productfeatures.Add(productfeature);
}
// Next Result
rdr.NextResult();
while (rdr.Read())
{
ProductCategory productcategory = new ProductCategory();
productcategory.CategoryId = Convert.ToInt32(rdr["CategoryId"]);
productcategory.CategoryName = Convert.ToString(rdr["CategoryName"]);
productcategories.Add(productcategory);
}
listProductCategoryAndFeature.productfeatures = productfeatures;
listProductCategoryAndFeature.productcategories = productcategories;
CloseConnection();
return listProductCategoryAndFeature;
}
public void UpdateProductAndFeatures(Product product)
{
try
{
int i = ExecNonQueryProc("Usp_UpdateProductsAndFeatures",
new SqlParameter("@ProductId", product.ProductId),
new SqlParameter("@ProductName", product.ProductName),
new SqlParameter("@CategoryId", product.CategoryId),
new SqlParameter("@QuantityPerUnit", product.QuantityPerUnit),
new SqlParameter("@UnitPrice", product.UnitPrice),
new SqlParameter("@ProductFeatures", product.ProductFeature));
}
catch
{
throw;
}
finally
{
CloseConnection();
}
}
public void UpdateProductImage(Product product)
{
try
{
int i = ExecNonQueryProc("SP_UpdateProductImage",
new SqlParameter("@ProductId", product.ProductId),
new SqlParameter("@ImagePath", product.ImagePath));
}
catch
{
throw;
}
finally
{
CloseConnection();
}
}
public void DeleteProduct(Product product)
{
try
{
int i = ExecNonQueryProc("SP_DeleteProduct",
new SqlParameter("@ProductId", product.ProductId));
}
catch
{
throw;
}
finally
{
CloseConnection();
}
}
public void DeleteProductFeature(int fid)
{
try
{
int i = ExecNonQueryProc("SP_DeleteProductFeature",
new SqlParameter("@FeatureId", fid));
}
catch
{
throw;
}
finally
{
CloseConnection();
}
}
}
}
Step 5 : In Models :
Product.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace SampleMvc.Models
{
public class Product
{
public int ProductId { get; set; }
public int CategoryId { get; set; }
public string ProductName { get; set; }
public string ProductFeature { get; set; }
public DateTime CreateOn { get; set; }
public bool Discounted { get; set; }
public int UnitsInStock { get; set; }
public int QuantityPerUnit { get; set; }
public int UnitPrice { get; set; }
public string ImagePath { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace SampleMvc.Models
{
public class ListProductCategoryAndFeature
{
public List<ProductFeature> productfeatures { get; set; }
public List<ProductCategory> productcategories { get; set; }
}
}
Step 6: In Database Procedures and Functions along with tables :
Table 01 :
CREATE TABLE [dbo].[ProductFeatures](
[FeatureId] [int] IDENTITY(1,1) NOT NULL,
[ProductId] [int] NULL,
[ProductFeature] [nvarchar](max) NULL,
[Status] [bit] NOT NULL,
[IsDeleted] [bit] NOT NULL,
[CreatedOn] [date] NULL,
[OrderBy] [int] NULL,
CONSTRAINT [PK_ProductFeatures] PRIMARY KEY CLUSTERED
(
[FeatureId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[ProductFeatures] ADD CONSTRAINT [DF_ProductFeatures_Status] DEFAULT ((1)) FOR [Status]
GO
ALTER TABLE [dbo].[ProductFeatures] ADD CONSTRAINT [DF_ProductFeatures_IsDeleted] DEFAULT ((0)) FOR [IsDeleted]
Table 02 :
CREATE TABLE [dbo].[Products](
[ProductID] [int] IDENTITY(1,1) NOT NULL,
[ProductName] [nvarchar](40) NOT NULL,
[SupplierID] [int] NULL,
[CategoryID] [int] NULL,
[QuantityPerUnit] [nvarchar](20) NULL,
[UnitPrice] [money] NULL,
[UnitsInStock] [smallint] NULL,
[UnitsOnOrder] [smallint] NULL,
[ReorderLevel] [smallint] NULL,
[Discontinued] [bit] NOT NULL,
[CreatedOn] [date] NULL,
[ImagePath] [nvarchar](max) NULL,
CONSTRAINT [PK_Products] PRIMARY KEY CLUSTERED
(
[ProductID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
Function 01 :
CREATE FUNCTION [dbo].[func_Split]
(
@DelimitedString varchar(8000),
@Delimiter varchar(100)
)
RETURNS @tblArray TABLE
(
ElementID int IDENTITY(1,1), -- Array index
Element varchar(1000) -- Array element contents
)
AS
BEGIN
-- Local Variable Declarations
-- ---------------------------
DECLARE @Index smallint,
@Start smallint,
@DelSize smallint
SET @DelSize = LEN(@Delimiter)
-- Loop through source string and add elements to destination table array
-- ----------------------------------------------------------------------
WHILE LEN(@DelimitedString) > 0
BEGIN
SET @Index = CHARINDEX(@Delimiter, @DelimitedString)
IF @Index = 0
BEGIN
INSERT INTO
@tblArray
(Element)
VALUES
(LTRIM(RTRIM(@DelimitedString)))
BREAK
END
ELSE
BEGIN
INSERT INTO
@tblArray
(Element)
VALUES
(LTRIM(RTRIM(SUBSTRING(@DelimitedString, 1,@Index - 1))))
SET @Start = @Index + @DelSize
SET @DelimitedString = SUBSTRING(@DelimitedString, @Start , LEN(@DelimitedString) - @Start + 1)
END
END
RETURN
END
Procedure 01 :
CREATE PROCEDURE [dbo].[SP_UpdateProductFeatures]
(
@PId INT,
@CreatedDate DATETIME,
@element VARCHAR(MAX),
@delimiter VARCHAR(MAX)
)
AS
BEGIN
DECLARE @result BIT = 0;
DECLARE @fId INT;
SET @fId= (SELECT Element FROM dbo.func_split(@element, '+|+') where ElementID = 1)
IF (@fId = 0)
BEGIN
;WITH opt AS(
SELECT * FROM dbo.func_split(@element, '+|+')
)
INSERT INTO ProductFeatures
(
ProductId,
CreatedOn,
ProductFeature,
OrderBy
)
VALUES
(
@PId,
GETDATE(),
(select Element from opt where elementId = 2),
(select Element from opt where elementId = 4)
)
END
ELSE
BEGIN
;WITH opt AS(
SELECT * FROM dbo.func_split(@element, '+|+')
)
UPDATE ProductFeatures
SET ProductFeature = (select Element from opt where elementId = 2),
OrderBy = (select Element from opt where elementId = 4)
WHERE FeatureId=@fId
END
RETURN @result
END
Procedure 02 :
CREATE PROC [dbo].[Usp_UpdateProductsAndFeatures]
@ProductId INT,
@ProductName NVARCHAR(MAX),
@CategoryId INT,
@QuantityPerUnit INT,
@UnitPrice INT,
@ProductFeatures VARCHAR(MAX)
AS
BEGIN
DECLARE @PId INT
DECLARE @Feature VARCHAR(MAX)
Update Products
Set
ProductName = @ProductName,
CategoryID = @CategoryId,
QuantityPerUnit = @QuantityPerUnit,
UnitPrice = @UnitPrice
Where ProductID=@ProductId
SET @PId= @ProductId;
DECLARE @ExecQuery NVARCHAR(MAX);
SELECT @ExecQuery = COALESCE(@ExecQuery +';' ,'') + 'EXEC [dbo].[SP_UpdateProductFeatures] '+CAST(@PId AS VARCHAR)+', '''+ CAST(GETDATE() AS VARCHAR) +''', ''' + Element+''', ''+|+'''
FROM dbo.func_split(@ProductFeatures, '*|*');
EXECUTE sp_executesql @ExecQuery;
END
Procedure 03 :
Create Proc [dbo].[SP_DeleteProductFeature]
@FeatureId INT
AS
BEGIN
Delete ProductFeatures
Where FeatureId=@FeatureId
END
- We want to update all product details and its features along with its Image (In this example we taking 5 product at once) like as shown in figures below.
- Product Features are sortable and can be reordered using drag and drop list up or down.
Step 1 : In controller we have action methods to update products, its features, delete product and delete its feature.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using SampleMvc.Helpers;
using SampleMvc.Models;
using SampleMvc.DA;
using Newtonsoft.Json;
using System.IO;
namespace SampleMvc.Controllers
{
public class ManageProductController : Controller
{
public ActionResult Products()
{
ListProductCategoryAndFeature listProductCategoryAndFeature = new ListProductCategoryAndFeature();
List<Product> product = new List<Product>();
List<ProductFeature> productfeatures = new List<ProductFeature>();
ProductDA productDA = new ProductDA();
product = productDA.ReadAllProducts();
listProductCategoryAndFeature = productDA.ReadAllProductFeaturesAndCategory();
ViewBag.ProductFeatures = listProductCategoryAndFeature.productfeatures;
ViewBag.ProductCategories = listProductCategoryAndFeature.productcategories;
return View(product);
}
[HttpPost]
public ActionResult Products(string product)
{
var listProducts = JsonConvert.DeserializeObject<List<Product>>(product);
foreach (var prod in listProducts)
{
ProductDA productDA = new ProductDA();
productDA.UpdateProductAndFeatures(prod);
}
return Json(new { Success = true });
}
public ActionResult UpdateImage()
{
string imgName = string.Empty;
ProductDA productDA = new ProductDA();
if (System.Web.HttpContext.Current.Request.Files.AllKeys.Any())
{
for (int i = 0; i < System.Web.HttpContext.Current.Request.Files.Count; i++)
{
var pic = System.Web.HttpContext.Current.Request.Files[i];
var pid = System.Web.HttpContext.Current.Request.Form[i];
if (pic.ContentLength > 0)
{
var fileName = Path.GetFileName(pic.FileName);
var ext = Path.GetExtension(pic.FileName);
if (ext == ".jpg" || ext == ".png" || ext == ".jpeg" || ext == ".gif")
{
string imgPath = "";
imgPath = "/ProductImages/" + pid + ext;
Product prod = new Product();
prod.ProductId = Convert.ToInt32(pid);
prod.ImagePath = imgPath;
productDA.UpdateProductImage(prod);
// TODO : Crop Image before saving
string path = Server.MapPath(imgPath);
pic.SaveAs(path);
}
}
}
}
return Json(new { Success = true });
}
[HttpPost]
public ActionResult DeleteProduct(Product product)
{
ProductDA productDA = new ProductDA();
productDA.DeleteProduct(product);
return Json(new { Success = true });
}
[HttpPost]
public ActionResult DeleteProductFeature(int fid)
{
ProductDA productDA = new ProductDA();
productDA.DeleteProductFeature(fid);
return Json(new { Success = true });
}
}
}
Step 2 : In Views :
@{
ViewBag.Title = "Manage Product";
Layout = "~/Views/Shared/_Layout.cshtml";
}
@model List<SampleMvc.Models.Product>
@using SampleMvc.Models;
<div class="container-fluid">
<div class="row content">
<div class="col-sm-3 sidenav">
<h4>Manage Products</h4>
<ul class="nav nav-pills nav-stacked">
<li class="active"><a href="#section1">Home</a></li>
<li><a href="/Product/Product">Bulk Product Upload</a></li>
<li><a href="/ManageProduct/Products">Manage Products</a></li>
<li><a href="#section3">Photos</a></li>
</ul>
<br>
<div class="input-group">
<input type="text" class="form-control" placeholder="Search Blog..">
<span class="input-group-btn">
<button class="btn btn-default" type="button">
<span class="glyphicon glyphicon-search"></span>
</button>
</span>
</div>
</div>
<div class="col-sm-9">
<h4><small>Manage Products and its features.</small></h4>
<hr>
<div class="col-sm-12">
@foreach (var product in Model)
{
<div id="@string.Format("product{0}", product.ProductId)" class="manageProduct" pid="@product.ProductId">
<div class="row">
<div class="col-sm-3">
@(Model.IndexOf(product) + 1) )
Product Name :
</div>
<div class="col-sm-6">
<input type="text" class="form-control" id="@string.Format("txtProductName{0}", product.ProductId)" value="@product.ProductName" />
<div id="@string.Format("errProductName{0}", product.ProductId)" class="divErr"></div>
</div>
<div class="col-sm-3">
<a href="javascript:;" class ="btn btn-danger delProduct" title="Delete Product" pid="@product.ProductId">Delete</a>
</div>
</div>
<br />
<div class="row">
<div class="col-sm-3">
Product Features :
</div>
<div class="col-sm-6">
<ul class="list-group" id="@string.Format("choiceList{0}", product.ProductId)">
@foreach (var feature in (List<ProductFeature>)ViewBag.ProductFeatures)
{
if (feature.ProductId == product.ProductId)
{
<li class="list-group-item list-group-item-info" id="@string.Format("li{0}", feature.FeatureId)">
<div class="divOption fwidth">
<div class="divAnsOption hwidth">
<label class="rdAnsOption" type="text" name="choice" fid="@feature.FeatureId" value="@feature.ProdFeature" /> @feature.ProdFeature
</div>
<div class="divOrderBy">
<input type="text" class="rdAnsOrder form-control" value="@feature.OrderBy" style="width:44px"/>
</div>
<div class="divRemoveOpt"><a href="javascript:;" class="delChoice" fid="@feature.FeatureId" title="Remove Choice">X</a></div>
</div>
</li>
}
}
</ul>
<input type="button" id="@string.Format("btnAddFeature{0}", @product.ProductId)" class="btn btn-primary" value="Add Feature"/>
<div class="divAddOption" id="@string.Format("divAddOpt{0}", @product.ProductId)">
Enter Feature :
<input id="@string.Format("txtFeature{0}", @product.ProductId)" type="text" class="form-control" required="required" />
<div id="@string.Format("errFeature{0}", @product.ProductId)" class="divErr"></div><br />
<input type="button" id="@string.Format("btnAddOpt", @product.ProductId)" class="btn btn-primary" value="Add" />
</div>
</div>
<div class="col-sm-3">
</div>
</div>
<br />
<div class="row">
<div class="col-sm-3">
Product Category :
</div>
<div class="col-sm-6">
<select id="@string.Format("drpProductCategory{0}", product.ProductId)" class="form-control">
<option value="0">Select Category</option>
@foreach (var m in @ViewBag.ProductCategories)
{
if (m.CategoryId == product.CategoryId)
{
<option value= "@m.CategoryId" selected>@m.CategoryName </option>
}
else
{
<option value= "@m.CategoryId">@m.CategoryName </option>
}
}
</select>
<div id="@string.Format("errProductCategory{0}", product.ProductId)" class="divErr"></div>
</div>
<div class="col-sm-3">
</div>
</div>
<br />
<div class="row">
<div class="col-sm-3">
Quantity Per Unit :
</div>
<div class="col-sm-6">
<input type="text" class="form-control" id="@string.Format("txtQuantityPerUnit{0}", product.ProductId)" value="@Convert.ToInt32(product.QuantityPerUnit)" />
</div>
<div class="col-sm-3">
</div>
</div>
<br />
<div class="row">
<div class="col-sm-3">
Unit Price :
</div>
<div class="col-sm-6">
<input type="text" class="form-control" id="@string.Format("txtUnitPrice{0}", product.ProductId)" value="@Convert.ToInt32(product.UnitPrice)" />
</div>
<div class="col-sm-3">
</div>
</div>
<br />
<div class="row">
<div class="col-sm-3">
Product Image :
</div>
<div class="col-sm-6">
<input type="file" name="postedFile" id="@string.Format("imgProductImageUrl{0}", product.ProductId)" />
</div>
<div class="col-sm-3">
<img src="@Url.Content((string.IsNullOrEmpty(product.ImagePath) == true ? "/Images/noimage.png" : product.ImagePath))" alt="@product.ProductName" width="150px" />
</div>
</div>
<br />
</div>
}
<input type="button" value="Save" id="btnSaveProduct" class="btn btn-primary" />
</div>
</div>
</div>
</div>
@section scripts {
<script src="~/Scripts/ManageProducts.js"></script>
}
Step 3 : In Javascript File ManageProducts.js :
var productManage = {
init: function () {
$(".manageProduct").each(function () {
var id = $(this).attr("pid");
var divQues = '#ques' + id;
$("#choiceList" + id).sortable({
stop: function (event, ui) {
var sort = $('#choiceList' + id).find('input[type="text"]');
sort.each(function (index) {
$(this).val((index + 1));
});
}
});
$("#btnAddFeature" + id).click(function () {
$("#divAddOpt" + id).show();
$("#btnAddFeature" + id).hide();
});
$("#txtBaseValue" + id).keypress(function (event) {
$("#errBaseValue" + id).html("");
var key = event.which;
if (!(key >= 48 && key <= 57)) {
event.preventDefault();
$("#errBaseValue" + id).html("Only numeric value is allow.");
}
});
// Add choice
var addChoice = function (input) {
var val = $.trim($(input).val());
$("#choiceList" + id).append('<li class="list-group-item list-group-item-info" id="li' + id + '"><div class="divOption fwidth"><div class="divAnsOption hwidth"><label class="rdAnsOption" type="text" name="choice" fid="0" value="' + val + '" t="N" >' + val + '</label></div><div class="divOrderBy"><input type="text" class="rdAnsOrder form-control" style="width:44px" value="' + ($("#choiceList" + id + " li").length + 1) + '"/></div><div class="divRemoveOpt"><a href="javascript:;" class="delChoice" title="Remove Choice">X</a></div></div></li>');
$(input).val("");
$(".delChoice").click(function () {
var fid = $(this).attr("fid");
if (!fid) {
$(this).parent().parent().parent().remove();
productManage.sortOptions(id);
}
});
};
$(".delChoice").click(function () {
var fid = $(this).attr("fid");
if ($("#dialogdelete")) $("#dialogdelete").remove();
$("body").append("<div id='dialogdelete'>Do you want to delete this feature?</div>");
$("#dialogdelete").dialog({
modal: true,
title: 'Delete Feature',
width: 400,
buttons: {
Delete: function () {
alert(fid);
$(this).dialog("close");
$.ajax({
data: { fid: fid },
type: "POST",
url: "/ManageProduct/DeleteProductFeature",
success: function (data) {
if (data.Success) {
$("#li" + fid).remove();
productManage.sortOptions(id);
}
}
});
},
Cancel: function () {
$(this).dialog("close");
}
}
});
});
$("#txtFeature" + id).change(function () {
$("#errFeature" + id).html("");
if ($("#choiceList" + id + " li").length == 0) {
addChoice(this);
}
else {
var count = 0;
$("#choiceList" + id + " label").each(function (i) {
var addFeature = $.trim($(this).text());
if ($.trim($("#txtFeature" + id).val()).toLowerCase() == addFeature.toLowerCase()) {
count = count + 1;
}
else {
}
});
if (count == 0) {
addChoice($("#txtFeature" + id));
}
else {
$("#errFeature" + id).html("Feature already added.");
$("#txtFeature" + id).focus();
}
}
});
// This section has not been implemented here.
$("#drpFeatureType" + id).change(function () {
if ($("#drpFeatureType" + id + " option:selected").text() == "Text") {
if ($("#dialogdelete")) $("#dialogdelete").remove();
$("body").append("<div id='dialogdelete'>Do you want to delete all Feature?</div>");
$("#dialogdelete").dialog({
modal: true,
title: 'Delete All Feature',
width: 400,
buttons: {
Delete: function () {
$(this).dialog("close");
$.ajax({
data: { pid: id },
type: "POST",
url: "/ManageProduct/DeleteAllFeature",
success: function (data) {
if (data.Success) {
$("#choiceList" + id).empty();
$("#btnAddFeature" + id).hide();
productManage.sortOptions(id);
}
}
});
},
Cancel: function () {
$(this).dialog("close");
$("#drpQuestionType" + id).val("R");
}
}
});
}
else {
$("#btnAddFeature" + id).show();
}
});
});
},
validateProduct: function () {
var counterr = 0;
$(".manageProduct").each(function () {
counterr = 0;
var id = $(this).attr("pid");
$('span[id^="spnMsg"]').html("");
$('div[id^="err"]').html("");
if ($("#txtProductName" + id).val() == "") {
$("#txtProductName" + id).focus();
$("#errProductName" + id).html("Please enter Product Name.");
counterr++;
return false;
}
else if ($("#drpProductCategory" + id + " option:selected").val() == 0) {
$("#drpProductCategory" + id).focus();
$("#errProductCategory" + id).html("Please select Product Category.");
counterr++;
return false;
}
});
if (counterr > 0)
return false;
else
return true;
},
sortOptions: function (id) {
var sort = $('#choiceList' + id).find('input[type="text"]');
sort.each(function (index) {
$(this).val((index + 1));
});
}
};
$("#btnSaveProduct").click(function () {
if (productManage.validateProduct()) {
jsonProductObj = [];
var data = new FormData();
$(".manageProduct").each(function () {
var id = $(this).attr("pid");
product = {}
product["ProductId"] = id;
product["ProductName"] = $("#txtProductName" + id).val();
product["CategoryId"] = $("#drpProductCategory" + id + " option:selected").val();
product["QuantityPerUnit"] = $("#txtQuantityPerUnit" + id).val();
product["UnitPrice"] = $("#txtUnitPrice" + id).val();
//product["Discounted"] = $("#txtDiscount" + id).is(":checked");
var count = 0;
var ProductFeature = "";
$('#choiceList' + id + ' label').each(function (index) {
ProductFeature = ProductFeature + $(this).attr('fid') + "+|+" + $(this).attr('value') + "+|+" + $(this).is(':checked') + "+|+" + $(this).parent().parent().find('input:text').val() + "*|*";
if ($(this).is(':checked'))
count = count + 1;
});
product["ProductFeature"] = ProductFeature;
jsonProductObj.push(product);
// Adding images to formdata
var files = $("#imgProductImageUrl" + id).get(0).files;
if (files.length > 0) {
data.append("MyImages" + id, files[0]);
data.append("Pid" + id, id);
}
});
$.ajax({
type: 'post',
dataType: 'json',
url: '/ManageProduct/Products',
data: { "product": JSON.stringify(jsonProductObj) },
success: function (json) {
$.ajax({
url: "/ManageProduct/UpdateImage",
type: "POST",
processData: false,
contentType: false,
data: data,
success: function (response) {
window.location.href = '/ManageProduct/Products';
}
});
},
});
}
});
$(".delProduct").click(function () {
var product = {};
product.ProductId = $(this).attr("pid");
if ($("#dialogdelete")) $("#dialogdelete").remove();
$("body").append("<div id='dialogdelete'>Do you want to delete this Product?</div>");
$("#dialogdelete").dialog({
modal: true,
title: 'Delete Product',
width: 400,
buttons: {
Delete: function () {
$(this).dialog("close");
alert(product.ProductId);
$.ajax({
url: '/ManageProduct/DeleteProduct',
method: 'post',
data: '{product: ' + JSON.stringify(product) + '}',
contentType: "application/json; charset=utf-8",
success: function () {
window.location.reload(true);
},
error: function (err) {
}
});
},
Cancel: function () {
$(this).dialog("close");
}
}
});
});
$(document).ready(function () {
productManage.init();
});
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SampleMvc.Models;
using System.Data.SqlClient;
namespace SampleMvc.DA
{
public class ProductDA : SQLHelper
{
public void AddProductAndFeatures(Product product, string productFeature)
{
try
{
int i = ExecNonQueryProc("Usp_InsertProductAndFeatures",
new SqlParameter("@ProductName", product.ProductName),
new SqlParameter("@CategoryId", product.CategoryId),
new SqlParameter("@ProductFeatures", productFeature));
}
catch
{
throw;
}
finally
{
CloseConnection();
}
}
public List<Product> ReadAllProducts()
{
List<Product> products = new List<Product>();
SqlDataReader rdr = ExecDataReaderProc("Sp_ReadAllProducts");
while (rdr.Read())
{
Product product = new Product();
product.ProductId = Convert.ToInt32(rdr["ProductId"]);
product.ProductName = Convert.ToString(rdr["ProductName"]);
product.CategoryId = Convert.ToInt32(rdr["CategoryId"]);
//product.QuantityPerUnit = Convert.ToInt32(rdr["QuantityPerUnit"]);
//product.UnitPrice = Convert.ToInt32(rdr["UnitPrice"]);
product.ImagePath = Convert.ToString(rdr["ImagePath"]);
//product.UnitsInStock = Convert.ToInt32(rdr["UnitsInStock"]);
//product.Discounted = Convert.ToBoolean(rdr["Discounted"]);
//product.CreateOn = Convert.ToDateTime(rdr["CreateOn"]);
products.Add(product);
}
CloseConnection();
return products;
}
// Returning multiple result set from procedure.
public ListProductCategoryAndFeature ReadAllProductFeaturesAndCategory()
{
ListProductCategoryAndFeature listProductCategoryAndFeature = new ListProductCategoryAndFeature();
List<ProductFeature> productfeatures = new List<ProductFeature>();
List<ProductCategory> productcategories = new List<ProductCategory>();
SqlDataReader rdr = ExecDataReaderProc("Sp_ReadAllProductFeatures");
while (rdr.Read())
{
ProductFeature productfeature = new ProductFeature();
productfeature.ProductId = Convert.ToInt32(rdr["ProductId"]);
productfeature.ProdFeature = Convert.ToString(rdr["ProductFeature"]);
productfeature.FeatureId = Convert.ToInt32(rdr["FeatureId"]);
productfeatures.Add(productfeature);
}
// Next Result
rdr.NextResult();
while (rdr.Read())
{
ProductCategory productcategory = new ProductCategory();
productcategory.CategoryId = Convert.ToInt32(rdr["CategoryId"]);
productcategory.CategoryName = Convert.ToString(rdr["CategoryName"]);
productcategories.Add(productcategory);
}
listProductCategoryAndFeature.productfeatures = productfeatures;
listProductCategoryAndFeature.productcategories = productcategories;
CloseConnection();
return listProductCategoryAndFeature;
}
public void UpdateProductAndFeatures(Product product)
{
try
{
int i = ExecNonQueryProc("Usp_UpdateProductsAndFeatures",
new SqlParameter("@ProductId", product.ProductId),
new SqlParameter("@ProductName", product.ProductName),
new SqlParameter("@CategoryId", product.CategoryId),
new SqlParameter("@QuantityPerUnit", product.QuantityPerUnit),
new SqlParameter("@UnitPrice", product.UnitPrice),
new SqlParameter("@ProductFeatures", product.ProductFeature));
}
catch
{
throw;
}
finally
{
CloseConnection();
}
}
public void UpdateProductImage(Product product)
{
try
{
int i = ExecNonQueryProc("SP_UpdateProductImage",
new SqlParameter("@ProductId", product.ProductId),
new SqlParameter("@ImagePath", product.ImagePath));
}
catch
{
throw;
}
finally
{
CloseConnection();
}
}
public void DeleteProduct(Product product)
{
try
{
int i = ExecNonQueryProc("SP_DeleteProduct",
new SqlParameter("@ProductId", product.ProductId));
}
catch
{
throw;
}
finally
{
CloseConnection();
}
}
public void DeleteProductFeature(int fid)
{
try
{
int i = ExecNonQueryProc("SP_DeleteProductFeature",
new SqlParameter("@FeatureId", fid));
}
catch
{
throw;
}
finally
{
CloseConnection();
}
}
}
}
Step 5 : In Models :
Product.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace SampleMvc.Models
{
public class Product
{
public int ProductId { get; set; }
public int CategoryId { get; set; }
public string ProductName { get; set; }
public string ProductFeature { get; set; }
public DateTime CreateOn { get; set; }
public bool Discounted { get; set; }
public int UnitsInStock { get; set; }
public int QuantityPerUnit { get; set; }
public int UnitPrice { get; set; }
public string ImagePath { get; set; }
}
}
ProductFeature.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace SampleMvc.Models
{
public class ProductFeature
{
public int FeatureId { get; set; }
public int ProductId { get; set; }
public string ProdFeature { get; set; }
public int OrderBy { get; set; }
}
}
ListProductCategoryAndFeature.cs
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace SampleMvc.Models
{
public class ListProductCategoryAndFeature
{
public List<ProductFeature> productfeatures { get; set; }
public List<ProductCategory> productcategories { get; set; }
}
}
Table 01 :
CREATE TABLE [dbo].[ProductFeatures](
[FeatureId] [int] IDENTITY(1,1) NOT NULL,
[ProductId] [int] NULL,
[ProductFeature] [nvarchar](max) NULL,
[Status] [bit] NOT NULL,
[IsDeleted] [bit] NOT NULL,
[CreatedOn] [date] NULL,
[OrderBy] [int] NULL,
CONSTRAINT [PK_ProductFeatures] PRIMARY KEY CLUSTERED
(
[FeatureId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[ProductFeatures] ADD CONSTRAINT [DF_ProductFeatures_Status] DEFAULT ((1)) FOR [Status]
GO
ALTER TABLE [dbo].[ProductFeatures] ADD CONSTRAINT [DF_ProductFeatures_IsDeleted] DEFAULT ((0)) FOR [IsDeleted]
Table 02 :
CREATE TABLE [dbo].[Products](
[ProductID] [int] IDENTITY(1,1) NOT NULL,
[ProductName] [nvarchar](40) NOT NULL,
[SupplierID] [int] NULL,
[CategoryID] [int] NULL,
[QuantityPerUnit] [nvarchar](20) NULL,
[UnitPrice] [money] NULL,
[UnitsInStock] [smallint] NULL,
[UnitsOnOrder] [smallint] NULL,
[ReorderLevel] [smallint] NULL,
[Discontinued] [bit] NOT NULL,
[CreatedOn] [date] NULL,
[ImagePath] [nvarchar](max) NULL,
CONSTRAINT [PK_Products] PRIMARY KEY CLUSTERED
(
[ProductID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
Function 01 :
CREATE FUNCTION [dbo].[func_Split]
(
@DelimitedString varchar(8000),
@Delimiter varchar(100)
)
RETURNS @tblArray TABLE
(
ElementID int IDENTITY(1,1), -- Array index
Element varchar(1000) -- Array element contents
)
AS
BEGIN
-- Local Variable Declarations
-- ---------------------------
DECLARE @Index smallint,
@Start smallint,
@DelSize smallint
SET @DelSize = LEN(@Delimiter)
-- Loop through source string and add elements to destination table array
-- ----------------------------------------------------------------------
WHILE LEN(@DelimitedString) > 0
BEGIN
SET @Index = CHARINDEX(@Delimiter, @DelimitedString)
IF @Index = 0
BEGIN
INSERT INTO
@tblArray
(Element)
VALUES
(LTRIM(RTRIM(@DelimitedString)))
BREAK
END
ELSE
BEGIN
INSERT INTO
@tblArray
(Element)
VALUES
(LTRIM(RTRIM(SUBSTRING(@DelimitedString, 1,@Index - 1))))
SET @Start = @Index + @DelSize
SET @DelimitedString = SUBSTRING(@DelimitedString, @Start , LEN(@DelimitedString) - @Start + 1)
END
END
RETURN
END
Procedure 01 :
CREATE PROCEDURE [dbo].[SP_UpdateProductFeatures]
(
@PId INT,
@CreatedDate DATETIME,
@element VARCHAR(MAX),
@delimiter VARCHAR(MAX)
)
AS
BEGIN
DECLARE @result BIT = 0;
DECLARE @fId INT;
SET @fId= (SELECT Element FROM dbo.func_split(@element, '+|+') where ElementID = 1)
IF (@fId = 0)
BEGIN
;WITH opt AS(
SELECT * FROM dbo.func_split(@element, '+|+')
)
INSERT INTO ProductFeatures
(
ProductId,
CreatedOn,
ProductFeature,
OrderBy
)
VALUES
(
@PId,
GETDATE(),
(select Element from opt where elementId = 2),
(select Element from opt where elementId = 4)
)
END
ELSE
BEGIN
;WITH opt AS(
SELECT * FROM dbo.func_split(@element, '+|+')
)
UPDATE ProductFeatures
SET ProductFeature = (select Element from opt where elementId = 2),
OrderBy = (select Element from opt where elementId = 4)
WHERE FeatureId=@fId
END
RETURN @result
END
Procedure 02 :
CREATE PROC [dbo].[Usp_UpdateProductsAndFeatures]
@ProductId INT,
@ProductName NVARCHAR(MAX),
@CategoryId INT,
@QuantityPerUnit INT,
@UnitPrice INT,
@ProductFeatures VARCHAR(MAX)
AS
BEGIN
DECLARE @PId INT
DECLARE @Feature VARCHAR(MAX)
Update Products
Set
ProductName = @ProductName,
CategoryID = @CategoryId,
QuantityPerUnit = @QuantityPerUnit,
UnitPrice = @UnitPrice
Where ProductID=@ProductId
SET @PId= @ProductId;
DECLARE @ExecQuery NVARCHAR(MAX);
SELECT @ExecQuery = COALESCE(@ExecQuery +';' ,'') + 'EXEC [dbo].[SP_UpdateProductFeatures] '+CAST(@PId AS VARCHAR)+', '''+ CAST(GETDATE() AS VARCHAR) +''', ''' + Element+''', ''+|+'''
FROM dbo.func_split(@ProductFeatures, '*|*');
EXECUTE sp_executesql @ExecQuery;
END
Procedure 03 :
Create Proc [dbo].[SP_DeleteProductFeature]
@FeatureId INT
AS
BEGIN
Delete ProductFeatures
Where FeatureId=@FeatureId
END