Wakanda Datastore - Find and Replace? - wakanda

I've got a lot of values in a legacy Wakanda datastore which I need to update to some new values. Is there a curl-like command in the wakanda data browser page that can be used to do a mass find-and-replace in a table?

If your dataclass is called MyDataClass and the attribute you want to update is myAttribute you can use the following server-side script :
var newValue = "new value";
ds.MyDataClass.all().forEach(function(entity){
entity.myAttribute = newValue;
entity.save();
});
You can also use a transaction if you want to commit or rollback the whole operation

I don't think there is a way to do a mass of find/replace in the dataBrowser,
But I suggest you to use a query in the server side that search the records with the value you need to replace, and then a loop on this collection to set the new values

As mentioned in other answers, you are likely best to loop over a collection. There is no concept of a mass replace in Wakanda like you see in many other databases.
var myCollection = ds.DataClassName.query("attributeName == :1", "valueToFind");
myCollection.forEach(function(e){
e.attributeName = "newValue";
e.save();
});
So a fake "person" data type might look like this:
var blankFirsts = ds.Person.query("firstname == :1", "");
blankFirsts.forEach(function(person){
person.firstname = "no name";
person.save();
});

Related

Nopcommerce update customise table when check out

I am newbie for nopcommerce.
Any Idea to check and update customise table when check out?
My case is like that:
I have create a new table name as "DailyLimit" table in my db.
Table field have ID,Date,DailyLimit.
when checkout product, I need to check the "Date" of Daily limit. If daily limit <= 0, then it will pop-up a alert, else it will update to DailyLimit field.
PS:I already create a date checkout attribute and make it as session.
For the Checkout controller I have add the availableQty variable pass to model.
public ActionResult OnePageCheckout(){
//validation
var cart = _workContext.CurrentCustomer.ShoppingCartItems
.Where(sci => sci.ShoppingCartType == ShoppingCartType.ShoppingCart)
.LimitPerStore(_storeContext.CurrentStore.Id)
.ToList();
//Problem here
var availableQtyFromDB = "SELECT DailyLimit FROM deliveryTbl WHERE date =Session["DeliveryDateForDesley"]" //problem here
if (cart.Count == 0)
return RedirectToRoute("ShoppingCart");
if (!_orderSettings.OnePageCheckoutEnabled)
return RedirectToRoute("Checkout");
if ((_workContext.CurrentCustomer.IsGuest() && !_orderSettings.AnonymousCheckoutAllowed))
return new HttpUnauthorizedResult();
var model = new OnePageCheckoutModel
{
ShippingRequired = cart.RequiresShipping(),
DisableBillingAddressCheckoutStep = _orderSettings.DisableBillingAddressCheckoutStep,
availableQty = availableQtyFromDB
};
return View(model);
}
But I have no idea how to write the how to SELECT statement in this controller.
And no idea how to update the daily limit.
Interesting question. Based on your code, I assume you haven't worked much with EF framework. when i started working with nopcommerce, i was like that too. But best thing in nopcommerce is most of common problems were solved in somewhere other part of the application.
First, blindly writing SQL in controller wont help much. Good way to learn is to have a look at
.LimitPerStore(_storeContext.CurrentStore.Id)
Method and how they have done the query/selection using Entity framework. They have done that for per store. You need to do it per day. That will help you to alight your solution in line with nopcommerce architecture.
Source: Ex-nopCommerce Developer for 3 years.

Updating an Entity Without Saving the Data back to the Database

I have created a new query like the following
var pressData = from press in dataContext.Releases
select new
{
Heading = press.Heading,
Description = press.Desc,
DatePublished = press.PublishDate.ToString(),
Body = press.BodyContent,
ID=press.ReleaseID,
CreatedBy=press.CreatedBy
};
Later in the code I want to update the entity from a session variable, but not save any data back to the database. Here is the code I am trying to accomplish this with....
var edit = pressData.Where(a => a.Heading == sectionPreview.HeadingContent && a.ID == sectionPreview.tionID).FirstOrDefault();
if (edit != null)
{
//WONT LET ME UPDATE THE Body VALUE
edit.Body = sectionPreview.SectionContent;
}
The code aboves purpose is to look at pressData and replace the body content with the new body from a session variable(not shown here), but NOT save it to the db. I want pressData to be filtered and updated only in the entity. So when I bind it to the control in this case it binds the data stored in my session.
this.rptSections.DataSource = pressData;
this.rptSections.DataBind();
I am getting a complier error stating
Property or indexer 'AnonymousType#1.Body' cannot be assigned to -- it is read only.
I checked the entity model and nothing is read only not any fields not anything. I must be missing something?
Anonymous Types encapsulate a read only property collection - for more information, read here. The compiler rewrites anonymous types as a constructor injections, ie:
select new
{
Heading = press.Heading,
Description = press.Desc,
DatePublished = press.PublishDate.ToString(),
Body = press.BodyContent,
ID=press.ReleaseID,
CreatedBy=press.CreatedBy
};
Is really rewritten as:
new Anonymous`1(press.Heading, press.Desc, press.PublishDate.ToString(), press.BodyContent, press.ReleaseID, press.CreatedBy)
And the properties are read only (public get, private / protected set, to use an easy comparison). If you want to solve your issue, instead of taking the data and making an anonymous object, create a real type and set properties on it.

Table with a foreign key

how can I build a table of "orders" containing "IdOrder", "Description" and "User"?... the "User" field is a reference to the table "Users", which has "IdUser" and "Name". I'm using repositories.
I have this repository:
Repository<Orders> ordersRepo = new OrderRepo<Orders>(unitOfWork.Session);
to return all Orders to View, I just do:
return View(ordersRepo.All());
But this will result in something like:
IdOrder:1 -- Description: SomeTest -- User: UserProxy123ih12i3123ih12i3uh123
-
When the expected result was:
IdOrder:1 -- Description: SomeTest -- User: Thiago.
PS: I don't know why it returns this "UserProxy123ih12i3123ih12i3uh123". In Db there is a valid value.
The View:
It is showed in a foreach (var item in Model).
#item.Description
#item.User //--> If it is #item.User.Name doesn't work.
What I have to do to put the Name on this list? May I have to do a query using LINQ - NHibernate?
Tks.
What type of ORM are you using? You mention "repositories" but does that mean LinqToSql, Entity Framework, NHibernate, or other?
It looks like you are getting an error because the User field is not loaded as part of the original query. This is likely done to reduce the size of the result set by excluding the related fields from the original query for Orders.
There are a couple of options to work around this:
Set up the repository (or context, depending on the ORM) to include the User property in the result set.
Explicitly load the User property before you access it. Note that this would be an additional round-trip to the database and should not be done in a loop.
In cases where you know that you need the User information it would make sense to ensure that this data in returned from the original query. If you are using LinqToSql take a look at the DataLoadOptions type. You can use this type to specify which relationships you want to retrieve with the query:
var options = new DataLoadOptions();
options.LoadWith<Orders>(o => o.User);
DataContext context = ...;
context.LoadOptions = options;
var query = from o in context.Orders
select o;
There should be similar methods to achive the same thing whatever ORM you are using.
In NHibernate you can do the following:
using (ISession session = SessionFactory.OpenSession())
{
var orders = session.Get<Order>(someId);
NHibernateUtil.Initialize(orders.User);
}
This will result in only two database trips (regardless of the number of orders returned). More information on this can be found here.
In asp.net MVC the foreign key doesn't work the way you are using it. I believe you have to set the user to a variable like this:
User user = #item.User;
Or you have to load the reference sometimes. I don't know why this is but in my experience if I put this line before doing something with a foreign key it works
#item.UserReference.load();
Maybe when you access item.User.Name the session is already closed so NHib cannot load appropriate user from the DB.
You can create some model and initialize it with proper values at the controller. Also you can disable lazy loading for Orders.User in your mapping.
But maybe it is an other problem. What do you have when accessing "#item.User.Name" from your View?

Can you sort Typed DataSet DataTables with Linq OrderBy?

I have a Typed DataSet DataTable which inherits TypedTableBase<T>, which in turn implements IEnumerable<T>. I can't seem to get this to work.
myDataTable.OrderBy(x => x.ID).ThenBy(y => y.ID2);
Instead I have to assign this statement to an IEnumerable(or List), then refill my DataTable manually with the newly ordered IEnumerable before I commit. Is this how it is intended to be? I've thought about creating my own extension method that will empty/refill my DataTables, but would this be wise?
Note: Typically I only need to sort for viewing purposes using DataView. But in this case I have a custom routine that must create a new access database with sorting requirements, which means I need to sort the actual DataTable so that I may re-commit it.
Thank you.
In order to do what you want, you must add the following reference to your project:
System.Data.DataSetExtensions
Once you have that added, you can order your DataTable like this:
var query = myDataTable.OrderBy(x => x.ID).ThenBy(y => y.ID2);
// use the DataView generated from the LINQ query
DataView dtv = query.AsDataView();
In order to iterate through the DataView, you can do the following:
var dtv = query.AsDataView();
foreach(DataRowView rw in dtv)
{
// you can also cast back to the typed data...
MyCustomRowType typedRow = (MyCustomRowType) rw.Row;
// do something here...
}
Alternatively you can typecast via LINQ this way:
var dtv = query.AsDataView().Cast<MyCustomRowType>();
// rowItem is of type MyCustomRowType...
foreach(var rowItem in dtv)
{
// do something here...
}
Linq extension methods do not alter the source enumerable.
var numbers = new int[]{1,2,3};
var reversed = numbers.OrderByDescending(x=>x);
foreach(var number in reversed)
Console.Write(number); // 321
foreach(var number in numbers)
Console.Write(number); // 123
If you want to sort a DataTable, you should be using DataViews. You create a view on your DataTable, then apply a Sort or Filter to it, then bind against it. Keep in mind DataSets are an older technology and not quite up to date on the latest and the greatest. A "newer" approach would be to use the Entity Framework.

Handling parameters from dynamic form for one-to-many relationships in grails

My main question here is dealing with the pramas map when having a one-to-many relationship managed within one dynamic form, as well as best practices for dealing with one-to-many when editing/updating a domain object through the dynamic form. The inputs for my questions are as follows.
I have managed to hack away a form that allows me to create the domain objects shown below in one Dynamic form, since there is no point in having a separate form for creating phone numbers and then assigning them to a contact, it makes sense to just create everything in one form in my application. I managed to implement something similar to what I have asked in my Previous Question (thanks for the people who helped out)
class Contact{
String firstName
String lastName
// ....
// some other properties
// ...
static hasMany = [phones:Phone]
static mapping = {
phones sort:"index", cascade: "all-delete-orphan"
}
}
class Phone{
int index
String number
String type
Contact contact
static belongsTo = [contact:Contact]
}
I basically managed to get the values from the 'params' map and parse them on my own and create the domain object and association manually. I.e. i did not use the same logic that is used in the default scaffolding, i.e.
Contact c = new Contact(params)
etc...., i just looped through all the params and hand crafted my domain objects and saved them and everything works out fine.
My controller has code blocks that look like this (this is stripped down, just to show a point)
//create the contact by handpicking params values
def cntct = new Contact()
cntct.firstName = params.firstName
cntct.lastName = params.lastName
//etc...
//get array of values for number,type
def numbers = params['phone.number']
def types = params['phone.type']
//loop through one of the arrays and create the phones
numbers.eachWithIndex(){ num, i ->
//create the phone domain object from
def phone = new Phone()
phone.number = num
phone.type = types[i]
phone.index = i
cntct.addToPhones(phone)
}
//save
My questions are as follows:
What is the best practice of handeling such a situation, would using Command objects work in this case, if yes where can i found more info about this, all the examples I have found during my search deal with one-to-one relationships, I couldn't find an example for one-to-many?
What is the best way to deal with the relatiohsips of the phones in this case, in terms of add/removing phones when editing the contact object. I mean the creation logic is simple since I have to always create new phones on save, but when dealing with updating a contact, the user might have removed a phone and/or editing an exiting one and/or added some new phones. Right now what I do is just delete all the phones a contact has and re-create them according to what was posted by the form, but I feel that's not the best way to do it, I also don't think looping over the existing ones and comparing with the posted values and doing a manual diff is the best way to do it either, is there a best practice on how to deal with this?
Thanks, hopefully the questions are clear.
[edit] Just for more information, phone information can be added and deleted dynamically using javascript (jquery) within the form [/edit]
disclaimer: i do not know if the following approach works when using grails. Let me know later.
See better way for dynamic forms. The author says:
To add LineItems I have some js that calculates the new index and adds that to the DOM. When deleting a LineItem i have to renumber all the indexes and it is what i would like to avoid
So what i do
I have a variable which stores the next index
var nextIndex = 0;
When the page is loaded, i perform a JavaScript function which calculates how many child The collection has and configure nextIndex variable. You can use JQuery or YUI, feel free.
Adding a child statically
I create a variable which store the template (Notice {index})
var child = "<div>"
+= "<div>"
+= "<label>Name</label>"
+= "<input type="text" name=\"childList[{index}].name\"/>"
+= "</div>"
+= "</div>"
When the user click on the Add child button, i replace {index} - by using regex - by the value stored in the nextIndex variable and increment by one. Then i add to the DOM
See also Add and Remove HTML elements dynamically with Javascript
Adding a child dinamically
Here you can see The Paolo Bergantino solution
By removing
But i think it is the issue grow up when deleting. No matter how many child you remove, does not touch on the nextIndex variable. See here
/**
* var nextIndex = 3;
*/
<input type="text" name="childList[0].name"/>
<input type="text" name="childList[1].name"/> // It will be removed
<input type="text" name="childList[2].name"/>
Suppose i remove childList1 What i do ??? Should i renumber all the indexes ???
On the server side i use AutoPopulatingList. Because childList1 has been removed, AutoPopulatingList handles it as null. So on the initialization i do
List<Child> childList = new AutoPopulatingList(new ElementFactory() {
public Object createElement(int index) throws ElementInstantiationException {
/**
* remove any null value added
*/
childList.removeAll(Collections.singletonList(null));
return new Child();
}
});
This way, my collection just contains two child (without any null value) and i do not need to renumber all the indexes on the client side
About adding/removing you can see this link where i show a scenario wich can gives you some insight.
See also Grails UI plugin
Thanks,
Your answer brought some insight for me to do a wider search and I actually found a great post that covers all the inputs in my question. This is just a reference for anyone reading this. I will write a blog entry on how I implemented my case soon, but this link should provide a good source of ino with a working exmaple.
http://www.2paths.com/2009/10/01/one-to-many-relationships-in-grails-forms/
Most of the time I use ajax to manage such problem.
So when the user clicks add new phone I get the template UI from the server for manageability purpose ( the UI just same GSP template that I use to edit, update the phone), so this way you are not mixing your UI with your js code, whenever you want to change the UI you have to deal only with our GSP code.
Then after getting the UI I add it to the page using jquery DOM manipulation. Then after filling the form when they hit add(save) the request is sent to the server via ajax and is persisted immediately.
When the user clicks edit phone the same UI template is loaded from the server filled with existing phone data, then clicking update will update the corresponding phone immediately via ajax, and same thing applies to delete operation.
But one day I got an additional scenario for the use case that says, "until I say save contact no phone shall be saved on the backend, also after adding phones to the contact on the ui if navigate away to another page and come back later to the contact page the phones I added before must be still there." ugh..
To do this I started using the Session, so the above operations I explained will act on the phone list object I stored on the session instead of the DB. This is simple perform all the operation on the phonesInSession but finally dont forget to do this(delete update):
phonesToBeDeleted = phonesInDB - phonesInSession
phonesToBeDeleted.each{
contact.removeFromPhones(it)
it.delete()
}
I know I dont have to put a lot of data in session but this is the only solution I got for my scenario.
If someone has got similar problem/solution please leave a comment.
First, in all your input fields names you add an #:
<input type="text" name="references[#].name"/>
Second, add call a function before submitting:
<g:form action="save" onsubmit="replaceAllWildCardsWithConsecutiveNumbers();">
Third, this is the code for the function that you call before submitting the form:
function replaceAllWildCardsWithConsecutiveNumbers(){
var inputs = $('form').find("[name*='#']");
var names = $.map(inputs, function(el) { return el.name });
var uniqueNames = unique(names);
for (index in uniqueNames) {
var uniqueName = uniqueNames[index];
replaceWildCardsWithConsecutiveNumbers("input", uniqueName);
replaceWildCardsWithConsecutiveNumbers("select", uniqueName);
}
}
function unique(array){
return array.filter(function(el, index, arr) {
return index === arr.indexOf(el);
});
}
function replaceWildCardsWithConsecutiveNumbers(inputName, name){
counter = 0;
$(inputName + "[name='" + name + "']").each(function (i, el) {
var curName = $(this).attr('name');
var newName = curName.replace("#", counter);
$(this).attr('name', newName);
counter += 1;
});
}
Basically, what the code for replaceAllWildCardsWithConsecutiveNumbers() does, is to create a list for all input (or select) elements whose name contains an #. Removes the duplicates. And then iterates over them replacing the # with a number.
This works great if you have a table and you are submitting the values to a command object's list when creating a domain class for the first time. If you are updating I guess you'll have to change the value of counter to something higher.
I hope this helps someone else since I was stuck on this issue for a while myself.

Resources