public static string SaveChanges(int parentID, string rows)
    {
        Dictionary <string, string> result = new Dictionary <string, string>()
        {
            { "saved", "" }, { "ids", "" }, { "error", "" }
        };
        bool   exists = false, saved = false;
        string ids = string.Empty, errorMsg = string.Empty, tempMsg = string.Empty;

        try
        {
            DataTable dtjson = (DataTable)JsonConvert.DeserializeObject(rows, (typeof(DataTable)));
            if (dtjson.Rows.Count == 0)
            {
                errorMsg = "Unable to save. An invalid list of changes was provided.";
                saved    = false;
            }

            int    id = 0, categoryId = 0, sortOrder = 0, archive = 0;
            int    assignedToID = 0, smeID = 0, busResourceID = 0, techResourceID = 0;
            string allocation = string.Empty, description = string.Empty;

            HttpServerUtility server = HttpContext.Current.Server;
            //save
            foreach (DataRow dr in dtjson.Rows)
            {
                id           = categoryId = sortOrder = archive = 0;
                assignedToID = smeID = busResourceID = techResourceID = 0;
                allocation   = description = string.Empty;

                tempMsg = string.Empty;
                int.TryParse(dr["ALLOCATIONID"].ToString(), out id);
                allocation  = server.UrlDecode(dr["ALLOCATION"].ToString());
                description = server.UrlDecode(dr["DESCRIPTION"].ToString());
                int.TryParse(dr["SORT_ORDER"].ToString(), out sortOrder);
                int.TryParse(dr["ARCHIVE"].ToString(), out archive);
                int.TryParse(dr["DefaultAssignedTo"].ToString(), out assignedToID);
                int.TryParse(dr["DefaultSME"].ToString(), out smeID);
                int.TryParse(dr["DefaultBusinessResource"].ToString(), out busResourceID);
                int.TryParse(dr["DefaultTechnicalResource"].ToString(), out techResourceID);

                if (string.IsNullOrWhiteSpace(allocation))
                {
                    tempMsg = "You must specify a value for Allocation.";
                    saved   = false;
                }
                else
                {
                    if (id == 0)
                    {
                        exists = false;
                        saved  = MasterData.AllocationGroup_Assignment_Add(allocationID: allocation, description: description, sortOrder: sortOrder, archive: archive == 1,
                                                                           defaultSMEID: smeID, defaultBusinessResourceID: busResourceID, defaultTechnicalResourceID: techResourceID, defaultAssignedToID: assignedToID,
                                                                           AllocationGroupID: parentID, exists: out exists, newID: out id, errorMsg: out tempMsg);
                        if (exists)
                        {
                            saved   = false;
                            tempMsg = string.Format("{0}{1}{2}", tempMsg, tempMsg.Length > 0 ? Environment.NewLine : "", "Cannot add duplicate Allocation record [" + allocation + "].");
                        }
                    }
                    else
                    {
                        saved = MasterData.AllocationGroup_Assignment_Update(id, allocation: allocation, description: description, sortOrder: sortOrder, archive: archive == 1, defaultSMEID: smeID, defaultAssignedToID: assignedToID, defaultBusinessResourceID: busResourceID, defaultTechnicalResourceID: techResourceID, errorMsg: out tempMsg);
                    }
                }

                if (saved)
                {
                    ids += string.Format("{0}{1}", ids.Length > 0 ? "," : "", id.ToString());
                }

                if (tempMsg.Length > 0)
                {
                    errorMsg = string.Format("{0}{1}{2}", errorMsg, errorMsg.Length > 0 ? Environment.NewLine : "", tempMsg);
                }
            }
        }
        catch (Exception ex)
        {
            saved    = false;
            errorMsg = ex.Message;
            LogUtility.LogException(ex);
        }

        result["ids"]   = ids;
        result["saved"] = saved.ToString();
        result["error"] = errorMsg;

        return(JsonConvert.SerializeObject(result, Formatting.None));
    }