Custom update in KendoUI datasource - oracle

I'm presenting a custom database view to the user in KendoUI, but my problem is that it's not updateable. My question is as follows: is there a way to write custom update behavior depending on which columns are being updated?
For instance, say I joined employees(id,name,dept_id) with department(id,dept_name) on department_id to form a table emp_dept(employee_id,employee_name,department_name). Say I was displaying emp_dept in Kendo and wanted to change the department names from the interface (and this was somehow impossible with a standard UPDATE statement). Could I write custom code for custom updates? For instance, in transport (and try not laugh at how basic/uninformed this looks as I'm still a noob):
update: {
url: function(options){
if(updating the employee name column)
return someserver:port/employees/employee_id
else if(updating the department name column)
return someserver:port/department/department_id
},
},
Hopefully you get the idea. Is this possible in KendoUI?

Related

Choose the first non-null field for each record in ServiceNow

How to create a view in ServiceNow that combines multiple columns (same data type) into one by picking the first non-null value? Note that it should not actually modify the underlying data.
After a search of the documentation I thought I had an answer with function fields, but GlideFunction doesn't seem to have nvl/coalesce as a function. The functionality called coalesce in ServiceNow seems to relate to importing/permanently modifying data only.
An example would be if you have employee and department, both of which have a location field. Show the employee's location unless it is null, otherwise show the employee's department's location.
In standard SQL, I would do it like this:
CREATE VIEW my_view AS (
SELECT COALESCE(employee.location,department.location) AS location
FROM employee JOIN department
ON employee.department_id = department.department_id
);
You have not mentioned how you are going to query this view. SNOW does not give us control over selection while designing views like the standard SQL.
Use GlideRecord to conditionally select the columns based on nullability.

Dealing with disassociated records in a poorly designed database

Overview
I have inherited a website that allows users to order customised products. The customisations were saved in a way that disassociates them from their record. I would like to modify the db so these records can be associated.
Example
Users can get Product #1 "stock", or customise it, changing as many as 10 different properties. Let's say color, fabric, width, height etc.
Orders can, and regularly do, contain multiple products, each of which may be customised.
Additionally, users can save their orders, so they can re-order later.
When the database was designed, the details of the order was neatly organised into individual columns. Customer name, address, payment type etc. But the list of products and more notably their customisations were saved as a JSON string in a single column. For ease, let's call this column the "cart".
Basically, the order table has a column cart and the cart column contains a JSON-formatted list of products and customisations.
Unfortunately, the JSON object has reference ids to the product table, but lacks references to the customisation table. Instead it uses a bunch of strings meant for a human to read. Fortunately those strings exist in the customisation table, but they were written as the cart was created.
The problem we face is that the list of customisations can be changed by a CMS. So far, they haven't been changed. 🙏 But they will need to be soon and that's going to cause problems:
Problems
If a customisation option is removed (say, a fabric option) and a customer re-orders from an old saved order, we need to be able to parse the cart, detect this and warn them of the change.
Customisations are currently immutable. Once a product is added to the cart, it cannot be changed. Users need to delete and re-add to make a single change. Poor UX.
If anyone changes the human-readable text on a customisation we're dead. ☠️
Questions
How would you design this if you were staring from scratch?
How might we go about converting the current implementation and legacy data to this new schema?
I don't know if stack is notable, but we're on Postgres and Django-Python.
I would implement this with the following tables:
Products {
productId // primary key
name
price
}
Customization_Types {
customizationTypeId // primary key
name // e.g. COLOR, FABRIC, LENGTH
}
Customizations {
customizationId // primary key
customizationTypeId // foreign key
value // e.g. BEIGE, VELVET, 8
}
Product_Customizations {
productCustomizationId // primary key
productId // foreign key
customizationId // foreign key
priceModifier // price markup for applying the customization
isValid // false if this record is invalid/obsolete
}
Orders {
orderId // primary key
customerId // foreign key
}
Product_Orders {
productOrderId // primary key
orderId // foreign key
productId // foreign key
quantity
}
Customization_Orders {
customizationOrderId // primary key
productOrderId // foreign key
productCustomizationId // foreign key
}
The Products table contains the data for your base products - name, price, etc
The Customization_Types table contains the type names for your different customizations - COLOR, FABRIC, LENGTH, etc
The Customizations table contains a link to a customizationTypeId as well as a legal value - I'm assuming that users can't enter arbitrary numerical values (for e.g. LENGTH or WIDTH) i.e. they're given a drop-down box instead of a text box, however if they can enter arbitrary numerical data then you'll need MIN/MAX fields that are null for named constraints (so e.g. you could have Type:COLOR/Value:BEIGE/Min:NULL/Max:NULL or Type:LENGTH/Value:NULL/Min:4/Max:8)
The Product_Customizations table links a Customization to a Product, so for example if ProductX can come in BEIGE then you would create a Product_Customization record that links ProductX to BEIGE.
The Orders table just contains an orderId and anything else relevant to the order (e.g. a link to the customerId and shippingAddressId)
Product_Orders links a product to an order
Customization_Orders links a Product_Customization to a Product_Order
Let's say a customer orders ProductX in BEIGE and LENGTH=8, then you would create an Order record, a Product_Order record with a link to ProductX, and two Customization_Order records - one linked to COLOR=BEIGE and one linked to LENGTH=8.
This should make it easy to modify a product's customizations without having to reload the entire product - the user can modify color to COLOR=RED without touching the length customization (delete the old Customization_Order:COLOR=BEIGE record and create a new COLOR=RED record), or the user can remove the length customization without touching the color customization (delete the old Customization_Order:LENGTH=8 record).
When reloading an old order/product you can quickly verify that the same productCustomizationIds still apply to the product in question, else flag the user. Additionally, you can flag the user if the customization still applies but the customization's price modifier has changed.
As far as converting the legacy data, I'm not familiar with Python but I do have experience with reading JSON via Java and I'm assuming that Python offers similar if not better libraries for this. The trick is going to be matching the existing data to pre-loaded Product_Customization data - if the data fails to match then create a new Product_Customization row corresponding to it with isValid=FALSE (this is assuming that the customization in question is no longer offered), and when you get a chance manually iterate through the invalid Product_Customization rows to ensure that these really are unmatched customizations and not just parsing errors.
Little improvement to Zim-Zam's answer.
Even better approach is to store not plain values (BEIGE, VELVET, 8) as customization parameters, but kind of schema from which code can build up correct view of a customization.
It could be just JSON/XML formatted text. And the entity that is responsible for building view and applying logic should be able to work with JSON data of different versions.
For example, if properties of a customization have changed and something new has been added, in that case you only need to change code and adjusted JSON will be saved. No need to change existing data. Also there should be possibility to read old JSON versions with old properties and work with it.
Two possible ways of what to do if you read an old entity from DB:
View builder will ignore all old properties of a customization, add new properties and set their values to default. I would go with that personally.
Old view is presented to user, but when user clicks, for example, Ok button or Finish, additional logic will check that there are old properties and notifies user that they should be removed manually or just removes them automatically.
More flexible approach that requires only code changes without touching db and allows to show user old customization properties if it is necessary.
Update:
Customizations could have two kind of properties: one that administrator can define, such as title or price, which are not frequently changed and common for all customizations and another one such as size and color which could be changed frequently, could have user defined values and are not common for all customizations.
The first kind should be stored in Customization table as separate columns. That will allow to changed such properties in administrative panel and have all previously stored data consistent.
The second kind of properties could be 1) frequently changed 2) not all customization types could have such properties. It is a bad idea to store them as separate columns because if there are huge amount of data, changing column type or adding new column could cause performance degradation and sometimes could not be possible due to incompatible types of properties.
Actually, if they are stored as separate columns, you are probably will have to change code to support new properties anyway.
My idea is that you still allow administrator to change type of such properties and add new one or remove old one through some interface. The key thing here is that you are storing JSON data like this
{
"properties": {
{
"propertyName": "height",
"propertyType": "int",
"min" : 10,
"max" : 25,
},
{
"propertyName": "color",
"propertyType": "color",
},
{
"propertyName": "anotherCustomField",
"propertyType": "text",
},
}
}
What's left to do is to implement view builders or renderers for all kinds of property type. And add a separate table with only values. You fetched a customization record from db, you found out which customization properties there are, checked which one are still valid and rendered only valid ones. If administrator changed type of customization's property or just removed one, you marked that customization's property as not valid in db and that's all the work. No code changes, no database schema changes.

creating a form field populated by a relationship in Laravel 4

I am trying to build a form for a Happening. The Happening references a Places table by place_id.
e.g. happening "OktoberFest" has a place_id 123 which corresponds in table Places to München
These are the relationships declared in the models:
For model Place:
public function happenings()
{
return $this->hasMany('Happening');
}
For model Happening:
public function place()
{
return $this->belongsTo('Place');
}
model Happening has a place_id field linking it to Place.
I am also using {{Form::model($happening, array('route' => array('happenings.update', $happening->id)...}} as form opening
Problem 1: how to create a {{Form::text('......')}} that will be properly prefilled with München when editing the happening Oktoberfest ?
Problem 2: I was trying to get that field to work as an ajax autosuggest (i.e. starting to pull suggestions from the Places table as soon as 3 characters have been entered). I have checked a few implementations but they don't seem to mix correctly with Problem 1
To try and solve Problem 1, I have tried the solution here
Laravel 4 Form builder Custom Fields Macro
but I was unable to make it work.
Long question, it's my very first on stack overflow, please be patient :)
If a Happening is linked to Place via the column 'place_id' you have to supply an id to save in your model/table.
There are a couple of ways that I can think of:
make a list of availble Places in a radio of select, the name will be 'place_id', the value the id of the Place en something like title for the value.
instead of displaying radio's or a select a textfield with autocomplete is a great solution if you got a lot of places. I won't go into detail how to implement it but the general idea is to autocomplete the typed in placename and on selection of that place to put the id of that place in a hidden field named 'placed_id'
After saving the form save your model with the posted place_id
(and check that id if it's valid and existing, never trust user input )

How to prevent user from modifying some fields on the form?

I am using MVC3 and EF4 to write a web application. I am using an action header like below to capture the form values submitted by the user.
<HttpPost()>
Public Function Edit(ByVal prod as Product) As ActionResult
I use the below code for updating the record.
db.Attach(prod)
db.ObjectStateManager.ChangeObjectState(prod, EntityState.Modified)
db.SaveChanges()
I get the submitted values in prod object which I update in the database. The problem is that there are some users who are not allowed to modify certain fields in a Product, say ProductCost. I have disabled the textboxes for such fields in the HTML. But since it is clientside, the user can easily enable it using some tool like Firebug and modify the value.
The only solution I could come up was to retrieve the existing record from the database and copy its ProductCost value into prod.ProductCost. But I don't like firing a query for achieving this. Is there a better way to achieve this?
Edit: I found the below link to update particular fields. How to update only one field using Entity Framework?
You can use the below code to modify a particular field.
context.ObjectStateManager.GetObjectStateEntry(user).SetModifiedProperty("FieldName");
Now the question is do I have to write the above statement for every field the user is able to modify? If yes, suppose the Product model has 10 fields (1 primary key) and the user is allowed to modify all of them except the primary key, I need to write 9 statements?? Is there a method where you can specify multiple properties at once. Or even better something where you specify the properties which are not modified. (Note: I know I can run a loop over an array of field names to avoid writing 9 statements. I am asking for an alternative method and not refactoring the above)
Never trust client data. Always have your server code to validate the input and do appropriate actions.
I would create separate overloads of my Respiratory method update the product in different ways and then check what is the current user's access type, If he is admin, i will call the overload which updates everything, if he is a manager, i will call the method which updates name,imageUrl and price and if he is an employee, i will call the method which updates only name and ImageURL
[HttpPost]
public ActionResult Edit(Product prod)
{
if(ModelState.IsValid)
{
string userType=GetCurrentUserTypeFromSomeWhere();
if(userType=="admin")
{
repo.UpdateProduct(prod);
}
else if(userType=="manager")
{
repo.UpdateProduct(prod.ID, prod.Name, prod.ImageUrl, prod.Price);
}
else if(userType=="employee")
{
repo.UpdateProduct(prod.ID, prod.Name, prod.ImageUrl);
}
return RedirectToAction("Updated",new {id=prod.ID});
}
}

LINQ and Devexpress Grid Datasource

I have a DevExpress grid (DevExpress.XtraGrid.GridControl 8.2) with a datasource set at runtime like so:
private DataContext db = new DataContext("connection string");
gridControl.DataSource = from t in db.sometable
select new
{
Field1 = t.Name,
Field2 = t.Email,
Field3 = t.City
};
This means that the view has no idea what the data is going to look like at design time. I like being able to set a LINQ query as the datasource, but I'd also like to specify what the view will look like at design time.
Is there a way that I can tell the view that it will be using this query?
Would the best solution be to create a small object for holding the
contents of what gets returned from
this query?
You will have to define a class for the return type of your LINQ query if you want the DevExpress grid to automatically pick up the columns for the data source. At design time, the WinForm binding engine is using reflection or ICustomTypeDescriptor if the source implements it to automatically discover the properties, their types, etc of the data source. The DevExpress grid is using this underlying binding mechanism and automatically generating the columns for you at design time based on the property information. In your case however, you're creating an anonymous type in your LINQ query which is not known or available at design time. Therefore, DevExress Grid cannot generate the columns automatically. As #Dennis mentioned, you can manually add columns to the grid in designer. You need to make sure that 'FieldName', I believe, on the column matches the property name on your data source.
If you go with a class, you may also want to implement INotifyPropertyChanged to make the grid aware of data changes in the data source.
IIRC, the xtragrid requires that the datasource implement a databinding interface (ie IBindingList(T)) for it to auto-generate columns and the items should implement INotifyPropertyChanged.
With that in mind: if you do create columns via the wizard at design time or in code at runtime, as long as you set the FieldName property of the columns, they will show the data from the datasource with a property of that name.
Notes:
I think it must be a property, auto or not, as I've found that it sometimes won't bind to public variables.
The property must be assigned something (default or otherwise).
There must be a parameterless constructor for the item.
The fields are known at design time (Field1, Field2, Field3).
According to DevExpress you can use IList, IListSource, ITypedList or IBindingList. The difference between them is whether you can add new rows or if changes are refin the control.
So you can use ToList():
private DataContext db = new DataContext("connection string");
gridControl.DataSource = (from t in db.sometable
select new
{
Field1 = t.Name,
Field2 = t.Email,
Field3 = t.City
}).ToList();
Note: I tested it using DevExpress 10.1, but if it does use the WinForms binding then it should still work according to MSDN.
I haven't worked with the DevExpress grid, but I've done a lot with the .NET DataGridView.
Does the DevExpress grid have the same functionality as the .NET DataGridView that auto generates columns?
If so, then it should display whatever fields are found in your query and will use Field1, Field2 and Field3 (from your example code) as column names.
Or just turn off the auto generate column feature and add the columns at design time. As long as they match what your query returns it should work fine.

Resources