I wrote a simple contract to verify that solidity refund gas when deleting storage.
pragma solidity >=0.7.0 <0.9.0;
contract Storage {
bool[] private data = [true, true, true, true, true, true, true, true, true, true,
true, true, true, true, true, true, true, true, true, true,
true, true, true, true, true, true, true, true, true, true,
true, true, true, true, true, true, true, true, true, true,
true, true, true, true, true, true, true, true, true, true
];
event Count(uint i);
function removeRange(bool isDelete) public returns(bool[] memory) {
for (uint j = 0; j < data.length; j++) {
emit Count(j);
if(!isDelete) {
continue;
}
delete data[j];
}
return data;
}
}
I added a counter to the methods to perform an operation which cost gas. Remix returned this in the logs when not deleting:
gas 151499 gas
transaction cost 131738 gas
execution cost 131738 gas
When I do call the function which deletes the storage nothing is refunded an infact my gas price is higher:
gas 186013 gas
transaction cost 152150 gas
execution cost 152150 gas
How can I verify gas refund functionality via solidity contract?
Data in a blockchain ( such as the Ethereum protocol ) can't be erased or modified. In Solidity, the delete keyword isn't used to free storage space, it just sets the current variable's value to 0, or false, or its "default value".
So as a matter of fact you'll be using more gas because you're actually sending a new transaction to the blockchain with the new value, and the allocated storage for your variables stays the same.
More info here.
PD: Just to clarify, as mentioned, in a blockchain you can't delete data nor modify it, that's why when developing with Solidity, when you update a state variable's value, you're actually sending a new transaction to the blockchain telling the blockchain what's the current state of that storage, but that doesn't mean that its previous value is erased, you can always access its last values by checking the transactions related to that storage variable.
Related
i just tried the SVF2 public beta.
I tried the translation on four models, but none of them worked. They are still in svf format and my cloud credits have been deducted.
As explained in the documentation, i just changed the output.formats.type to "svf2".
const job = {
input,
output: {
//force: true,
formats: [
{
views: ["2d", "3d"],
type: "svf2",
},
],
},
},
I am using node.js sdk version:
"forge-apis": "^0.7.3",
Viewer Version 7.29 with the init options:
const viewerEnv = await this.initialize({
// useConsolidation: true,
// env: dbModel.env,
// edgeRendering: true,
// lightPreset: "Boardwalk",
// envMapBackground: true,
// getAccessToken: function(onGetAccessToken) {
// onGetAccessToken(accessToken, expireTimeSeconds)
// }
env: "MD20ProdUS",
api: "D3S",
});
I checked the output-format with:
For all four translations, the translation-progress callback stopped between 90-98%. I never reached the 100% callback, but all models are translated.
we have not updated the node.js SDK yet for SVF2, so I suspect even with those changes, it may be reverting to SVF.
May be related to this open issue: instance.destroy(...) does not return any information if rows has been deleted or not but that seems to be more related to Model.destroy(...) which according to documentation should return the number of rows deleted.
I am new to Sequelize so please correct me if I am doing something wrong. I am using it with MySQL 8.0.16 and running sequelize 5.21.2
When using Model.findAll(...) and then looping through the rows and processing a Instance.destroy() I am being returned the instance per the Instance.destroy(...) documentation
db.tags.findAll({where: MyWhereObj, attributes: MyFieldArray}).then(tags => {
_.forEach(tags, tag => {
//more processing scripts for tag
tag.destroy().then(deleted => {
console.log(deleted)
})
})
})
What I would like to know is if the row was successfully deleted. I browsed through the returned instance looking if such an attribute like isNewRecord existed for isDeletedRecord but no similar
I can watch the node console and see the query come through correctly. Is it safe and best practice to assume the row was deleted successfully?
The query is sent to MySQL as...
DELETE FROM `tags` WHERE `guid` = 'aaa-bbb-ccc-ddd'
...which should the number of rows deleted, but Sequelize seems to ignore that information
I am thinking that I can catch a deletion error or a retrieving/processing error using these catch blocks. But wondering if there is a better way to simply know if the deletion took place or not
db.tags.findAll({where: MyWhereObj, attributes: MyFieldArray}).then(tags => {
_.forEach(tags, tag => {
// more processing scripts for tag
tag.destroy().then(deleted => {
console.log(deleted)
}).catch(err =>{
// The row was not deleted
console.error(err)
})
})
}).catch(err => {
// Error in Retrieving/Processing
console.error(err)
})
Note that there are two destroy methods:
https://sequelize.org/v6/class/src/model.js~Model.html#static-method-destroy
and
https://sequelize.org/v6/class/src/model.js~Model.html#instance-method-destroy
The v6 documentation says the static method returns Promise<number>, and the instance method returns a Promise (it does not specify what type the promise resolves to).
Also note that some methods return a different type for different dialects. For example, the model static method decrement documents its return value as:
Promise<Model[], ?number> returns an array of affected rows and affected count with options.returning true, whenever supported by dialect
Using sqlite dialect, I have found the destroy instance method to return a promise to the deleted model, not a promise to the deleted row count.
I think the documentation is incorrect, and (to answer your question), I don't think there is a simple way to confirm success of the deletion. I tried this:
const alloc = {code to get the model}
const alloc2 = alloc;
const deletedRowsCount = await alloc.destroy();
const destroy2Result = await alloc2.destroy();
and the when I logged the results with console.log({ deletedRowsCount, destroy2Result }), I got the exact same output for both destroys:
{
deletedRowsCount: allocs {
dataValues: {
id: 2,
amount: null,
locked: false,
createdAt: 2022-02-26T20:35:46.139Z,
updatedAt: 2022-02-26T20:35:46.139Z,
genLedgerAcctId: 9,
tranId: 1
},
_previousDataValues: {
id: 2,
amount: null,
locked: false,
createdAt: 2022-02-26T20:35:46.139Z,
updatedAt: 2022-02-26T20:35:46.139Z,
genLedgerAcctId: 9,
tranId: 1
},
_changed: Set(0) {},
_options: {
isNewRecord: false,
_schema: null,
_schemaDelimiter: '',
raw: true,
attributes: [Array]
},
isNewRecord: false
},
destroy2Result: allocs {
dataValues: {
id: 2,
amount: null,
locked: false,
createdAt: 2022-02-26T20:35:46.139Z,
updatedAt: 2022-02-26T20:35:46.139Z,
genLedgerAcctId: 9,
tranId: 1
},
_previousDataValues: {
id: 2,
amount: null,
locked: false,
createdAt: 2022-02-26T20:35:46.139Z,
updatedAt: 2022-02-26T20:35:46.139Z,
genLedgerAcctId: 9,
tranId: 1
},
_changed: Set(0) {},
_options: {
isNewRecord: false,
_schema: null,
_schemaDelimiter: '',
raw: true,
attributes: [Array]
},
isNewRecord: false
}
}
I plan to update this answer for other database types, in particular when I use a dialect that support foreign keys, so I can have a destroy that DOES fail.
I have a navigation grid, populated using the JSON data received from the controller.This data is stored as a JSON in database in single column.
$('#list-grid').jqGrid({
url: '#Url.Action("MyAction", "MyController")',
mtype: 'GET',
postData: { parameter1: para1, parameter2:para2 },
datatype: 'json',
gridview: true,
caption: ' ',
height: '100%',
multiselect: true,
rowNum: 5000,
viewrecords: true,
//colmodel and colnames
});
Now, I have added navigation bar to the grid.
jQuery("#list-grid").jqGrid('navGrid', '#list-grid3-pager',
{ edit: true, add: true, del: true, refresh: true, search: false, view: false, refreshtitle: "Clear filters", edittitle: "Edit selected record", addtitle: "Add new record" },
{
//this code executes on 'Submit' button in the dialog
//here, the selected row should be edited and edit should be reflected in the grid---in client-side
//then the whole grid has to be serialized,
//one more parameters has to be added
//and finally posted to the controller
}//edit option
Using a separate AJAX call, with a separate 'Save' button, I could have done like following to send the grid data, although this grid would still not have newly edited/added data:
$("#btnSave").click(function () {
var gridData = jQuery("#list-grid").getRowData();
var postGridData = JSON.stringify(gridData);
jQuery.ajax({
type: "POST",
url: '#Url.Action("MyAction2", "MyController")',
data: JSON.stringify({ parameter1: para1, gridValues: postGridData }),
contentType: "application/json; charset=utf-8",
dataType: "json",
});
}
My Question:
How do I add/edit rows in navigation grid, and after each add/edit Submit click, stringify the whole grid, (the added record should be there, and if any row has been edited, the string should contain the changed value and not the old one) , add a parameter and then pass it to the controller (just as you see in the ajax call) ?
This is my user model now before create user entity I want to auto give value session variable to createdBy and updatedBY.
module.exports = {
autoPK: false,
attributes: {
id:{columnName:'ID', type: 'integer', autoIncrement: true, primaryKey: true},
employeeId:{columnName:'EMPLOYEE_ID', type: 'string',unique : true},
firstName:{columnName:'FIRST_NAME', type: 'string'},
lastName:{columnName:'LAST_NAME', type: 'string'},
createdBy:{columnName:'CREATED_BY', model: 'user'},
updatedBy:{columnName:'CREATED_BY', model: 'user'},
},
beforeCreate: function(values, cb) {
values.createdBy=req.session.userId;
values.updatedBy=req.session.userId;
return values;
},
beforeUpdate: function(values, cb) {
values.updatedBy=req.session.userId;
return values;
},
}
I was looking for the same thing. Found some relevant resources that may help point you in the right direction. Unfortunately, there isn't great support to have sails automatically set UpdatedBy and CreatedBy properties on models.
https://stackoverflow.com/a/22855255/3085 - Use session param in model
https://stackoverflow.com/a/20998496/3085 - Access session data in Model hook
https://stackoverflow.com/a/22274325/3085 - Overriding blueprints
https://stackoverflow.com/a/21703180/3085 - Using model.js for model inheritance
I have same problem as Daniel had in this topic, but his solution doesn't work for me:
http://www.kendoui.com/forums/ui/grid/kendo-ui-grid-inserts-updates-create-duplicate-records.aspx#-jhxqRrNAUGsTFJaC-Ojwg
So use-case. Users adds 2 new records one after another:
Presses "Add new record" button of a grid
Fills the fields (name="Alex", amount=10, comment="first").
Record one is ready. Press 'Save'. (data goes to controller and than to Database)
User see one record in a grid
Press "Add new record" button again
Fills fields (name="Bob", amount=20, comment = "second").
Record one is ready. Press 'Save'. Data goes to controller and than to Database.
In this moment something happens and grid send Ajax request again with record one data to controller.
User updates grid and see three records
"Alex | 10 | first" (duplicated record) ID = 1
"Bob | 20 | second" ID = 2
"Alex | 10 | first" ID = 1
They recommend to return an ID for correct binding\update of data source with new record.
And I return it (new ID from database comes in response with bouns entity)! and this doesn't help.
Only if I add first record and refresh page with F5 and after that add second record everything is ok. But if add another one, the third records - problems appears again
Code in controller:
[HttpPost]
public JsonResult Create(BonusDto bonusDto)
{
BonusAggregate bonus;
if (bonusDto.Amount <= 0)
throw new ArgumentOutOfRangeException("Amount should be more than 0");
if (bonusDto.EmployeeId <= 0)
throw new ArgumentNullException("You should specify an existing employee");
using (var dbContext = new DatabaseContext())
{
BonusesRepository = new BonusesRepository(dbContext);
var employeeRepository = new EmployeesRepository(dbContext);
bonus = new BonusFactory(employeeRepository).Create(bonusDto);
BonusesRepository.Save(bonus);
}
HttpContext.Response.StatusCode = (int)HttpStatusCode.Created;
return Json(bonus); // try to return ID after bonus was saved
}
UI Code
// creates bonuses grid control
$("#bonusesGrid").kendoGrid({
dataSource: bonusesDataSource,
toolbar: ["create"],
editable: "inline",
columns: [
"BonusId",
"EmployeeId",
{
field: "EmployeeLastName",
editor: employeeAutocompletingEditor,
template: "#=EmployeeLastName#"
},
"Amount",
{
field: "Comment",
titel: "Comment",
editor: textareaEditor,
filterable: {
operators: {
number: {
contains: "Contains"
}
}
}
},
{
command: ["edit"],
title: " "
}
],
save: function(e) {
if (newValueEmployeeId !== undefined &&
newValueEmployeeLastName !== undefined &&
newValueEmployeeLastName !== "") {
setNewValueEmployeeIdAndLastName(newValueEmployeeId, newValueEmployeeLastName);
gridDataSource.model.EmployeeId = newValueEmployeeId; // it's a hack to bind model and autocomplete control
gridDataSource.model.EmployeeLastName = newValueEmployeeLastName;
} else {
gridDataSource.model.EmployeeId = currentValueEmployeeId;
gridDataSource.model.EmployeeLastName = currentValueEmployeeLastName;
}
},
edit: function(e) {
setCurrentValueEmployeeIdAndLastName(e.model.EmployeeId, e.model.EmployeeLastName);
},
cancel: function(e) {
setCurrentValueEmployeeIdAndLastName(e.model.EmployeeId, e.model.EmployeeLastName);
}
});
Bonus data source:
// bind json result from /Bonuses/GetPagedJsonBonuses
var bonusesDataSource = new kendo.data.DataSource({
transport: {
read: {
url: "#Url.Action("GetPagedJsonBonuses", "Bonuses")",
type : "GET",
contentType: "application/json",
dataType: "json",
cache: false
},
create: {
url: "#Url.Action("Create", "Bonuses")",
dataType: "json",
type: "POST"
},
parameterMap: function(options, operation) {
if (operation === "update" || operation === "create") {
// correct format for conversion
var d = new Date(options.Date);
options.Date = kendo.toString(d, dateFormat);
// updates the BonusDTO.EmployeeId with selected value
if (newValueEmployeeId !== undefined)
options.EmployeeId = newValueEmployeeId;
}
if(operation === "read") {
options.filter = setFormattedFilterDate(options.filter);
}
return options;
}
},
pageSize: 15,
serverPaging: true,
serverSorting: true,
serverFiltering: true,
error: showErrorMessage,
schema: {
data: "Data", // PagedResponse.Data
total: "TotalCount", // PagedResponse.TotalCount
model: {
id: "BonusId", // Data
fields: {
EmployeeId: { type: "number" },
EmployeeLastName: {
type: "string",
editable: true,
nulable: false,
validation: { required: {message: "Employee's last name is required"}}
},
Date: {
type: "date",
editable: true,
nullable: false,
validation: {
required: { message: "Date is required to be set" }
}
},
Amount: {
type: "number",
editable: true,
nullable: false,
defaultValue: 1,
validation: {
required: { message: "Amount is required to be set" }
}
},
Comment: { type: "string", editable: true }
} // fields
} // model
}// schema
});
I haven't seen this problem in my code. I do however have a "complete" event handler on my create and update events that refreshed the grid - it may help you:
dataSource: {
type: "jsonp",
transport: {
read: UrlBase + "getAll",
update: {
url: UrlBase + "Update",
dataType: "jsonp",
complete: function (e) {
$("#grid").data("kendoGrid").dataSource.read();
}
},
create: {
url: UrlBase + "create",
dataType: "jsonp",
complete: function (e) {
$("#grid").data("kendoGrid").dataSource.read();
}
},
destroy: {
url: UrlBase + "destroy",
dataType: "jsonp",
complete: function (e) {
$("#grid").data("kendoGrid").dataSource.read();
}
}
},
...
Yes, hamed is correct. Your "create" action result passes in the object from your model that is to be saved to your database. Have the INSERT in your data access layer return the newly created key ("ID") in the database. Use this key to now set the "ID" field on your model that's passed in to the action result and then passed back to the view as JSON. Now the grid should know it's just created this record and does not need to do anything more with it. Otherwise, the model object returns with the "ID" field set to 0 so the grid thinks it still needs to add this record.
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Grid_Create([DataSourceRequest] DataSourceRequest request, MyObject obj)
{
if (obj != null && ModelState.IsValid)
{
obj.Id = _myService.Create(obj);
}
return Json(new[] { obj }.ToDataSourceResult(request, ModelState));
}
This error occur when you did not pass Primary key to view in read action.
Regards
An alternative to Quinton Bernhardt's complete event: bind the dataSource.read() to the kendo sync event.
I'm using kendo's C# MVC's html helpers which don't expose the sync event, so I had to modify it after setting up the grid.
On window load:
var grid = $("#GridName").data("kendoGrid");
grid.dataSource.bind("sync", function () {
$("#GridName").data("kendoGrid").dataSource.read();
});
The sync event fires after the save request has been completed. The dataSource.read() gets the latest from the server, including the id that was set server side.
I had a similar issue, did various trials but fixed with the following trial
Jquery
create: {
type: "POST",
dataType: "json",
contentType: "application/json; charset=utf-8",
url: "../../ajax/ajaxGv.aspx/addstaff"
},
parameterMap: function (options, operation) {
if (operation == "create" && options.models) {
return JSON.stringify({ "oStaff": options.models });
}
VB.Net
'Adding Staff
<System.Web.Services.WebMethod()> _
Public Shared Sub addStaff(ByVal oStaff As Object)
Dim strJson As String = JsonConvert.SerializeObject(oStaff)
Dim lstStaff As List(Of Staff) = JsonConvert.DeserializeObject(Of List(Of Staff))(strJson)
Dim db As New LiveB2cDataContext
Try
db.Staff.InsertAllOnSubmit(lstStaff)
Next
db.SubmitChanges()
'Fix is that you need to return the objects you have added in the database back as json to kendo
strJson = JsonConvert.SerializeObject(lstStaff, Formatting.None)
WriteJson(strJson) ' Returning the objects added as json back to Kendo
Catch ex As Exception
ErrorLog(ex)
End Try
End Sub
Public Shared Sub WriteJson(strJson As String)
Try
HttpContext.Current.Response.Write(strJson)
HttpContext.Current.Response.Flush()
HttpContext.Current.ApplicationInstance.CompleteRequest()
HttpContext.Current.Response.SuppressContent = True
Catch ex As Exception
ErrorLog(ex)
End Try
End Sub
Fix is that you need to return the objects you have added in the database back as json to kendo
I'm not sure if this is part of your issue, but in your DataSource's schema model you specify that the ID is the field named "BonusId", but that field isn't specified in the array of fields.
I was having a simular issue.
I fixed it but making sure the id in the model is referring to a field:-
model: {
id: "Id",
fields: {
Id: { editable: false, type: "number" },
AnotherName: { editable: true, type: "string" },
AnotherId: { editable: true, type: "number" }
}
}
This may not solve the asker's problem, but hopefully might help someone with the same issue.
For us, this problem was being caused by errors being returned in JSON. Some required properties didn't have a value, but weren't related to the data we were displaying in the grid. Giving those properties a default value in the grid solved the issue.
You can view the JSON that's being returned by using Fiddler Web Debugging Tools.