How can I get Max value from table Id field based on a lookup filter in grid?
I have a grid which shows records from a table customer and a lookup filter with different locations. I want to set the Id field in the new form with the Max value from Customers in the Location lookup filter.
I can set the Id field to a static value like 99. But how can I set it to the max value of the customer table? My code below:
#Serenity.Decorators.registerClass()
export class UtentesGrid extends Serenity.EntityGrid<UtentesRow, any> {
protected getColumnsKey() { return 'IpssDB.Utentes'; }
protected getDialogType() { return UtentesDialog; }
protected getIdProperty() { return UtentesRow.idProperty; }
protected getInsertPermission() { return UtentesRow.insertPermission; }
protected getLocalTextPrefix() { return UtentesRow.localTextPrefix; }
protected getService() { return UtentesService.baseUrl; }
constructor(container: JQuery) {
super(container);
}
protected addButtonClick() {
this.editItem(<IpssDB.UtentesRow>{
Codigo: 99
});
}
}
Also is there an event, on the server side (endpoint maybe), that gets called when the add button is clicked and which can allow me to execute c# code? This would give more "freedom" to scan database as I please.
PS:
I managed to solve the problem like this:
Built a Helper:
public static GetUtenteNextNumberResponse GetUtenteNextNumber(IDbConnection connection, GetUtenteNextNumberRequest request)
{
var min = connection.Query<string>(new SqlQuery()
.From("Locais")
.Select("UtenteCodMin")
.Where("Codigo = " + request.Local))
.FirstOrDefault();
var minN = (string.IsNullOrEmpty(min) ? 0 : int.Parse(min));
var minCod = connection.Query<string>(new SqlQuery()
.From("Utentes")
.Select("Codigo")
.Where("Codigo >= " + minN ))
.FirstOrDefault();
var response = new GetUtenteNextNumberResponse();
var n = 0;
response.Number = minCod == null ||
!int.TryParse(minCod, out n) ? minN + 1 : n + 1;
return response;
}
And in the Grid.ts:
protected addButtonClick() {
var eq = this.view.params.EqualityFilter;
var local = 0
local = eq ? eq.Local : 0;
var ultCod = 0;
IPSS.IpssDB.UtentesService.GetUtenteNextNumber({
Local: local,
User: ''
}, response => {
this.editItem(<IpssDB.UtentesRow>{
Codigo: response.Number,
Local: eq ? eq.Local : null
});
});
}
Now the problem is the new form assumes that I am editing a record and not creating a new one and the button "Save" appears as "Update". I suppose it is because I am changing the key field.
Is there a way to overcome this? Or is there another way to go?
If there was an event or endpoint called when the Add new button in grid is clicked, which allowed to return the entity with default values, that would be perfect.
Problem solved!
I was trying to intercept the wrong event. The event i should be intercepting, but didn't know about, was loadEntity and not afterLoadEntity.
So i kept the helper with no change and just replaced the 'UtentesDialog.ts' code like this:
"UtentesDialog.ts"
protected loadEntity(data) {
super.loadEntity(data);
var local = 0;
local = data.Local;
if (this.isNew())
this.getNextNumber(local);
}
private getNextNumber(local) {
IPSS.IpssDB.UtentesService.GetUtenteNextNumber({
Local: local,
User: ''
}, response => {
this.form.Codigo.value = response.Number;
});
};
I also had to keep the addButtonClick in the 'UtentesGrid.ts' in order to obtain the Local value so i could get it in the Dialog form. Otherwise i wouldn't be able to get the value of Local filter (maybe there is another way, i don't know).
"UtentesGrid.ts"
protected addButtonClick() {
var eq = this.view.params.EqualityFilter;
var local = 0
local = eq ? eq.Local : 0;
this.editItem(<IpssDB.UtentesRow>{
//Codigo: ultCod,
Local: eq ? eq.Local : null
});
}
Related
Using the Podio.NET library (Podio.Async), I am trying to get a Podio View object using the ViewService.GetView() method. The Podio View object represents a predefined view, or set of filters, within a Podio Application.
One of the properties of the Podio View object (PodioAPI.Models.View) is the Items property, as in var noOfItems = myView.Items. However, this field always seems to return zero for me.
I guess that I can make a call to ItemService.FilterItemsByView() using the view-id, which in turn returns a PodioCollection<Item> object that has a FilteredItems property that can be used to get the number of items, but this would mean an additional call.
Does anyone have any thoughts or information that may help me?
Thanks for taking the time to read my question, and I hope that you can help, or others find this helpful.
Kaine
Example code
class Program
{
const string CLIENT_ID = "[Your Client Id]";
const string CLIENT_SECRET = "[Your Client Secret]";
const int APP_ID = [Your App Id];
const string APP_TOKEN = "[Your App Token]";
const string VIEW_NAME = "[Your View Id]";
static void Main(string[] args)
{
Task.Run(async () => { await Go(); }).GetAwaiter().GetResult();
Console.ReadKey();
}
static async Task Go()
{
var client = await GetClient();
var views = await GetViews(client);
var view = await GetView(client);
var viewItems = await GetViewItems(client, view);
}
static async Task<View> GetView(Podio client)
{
var view = await client.ViewService.GetView(APP_ID, VIEW_NAME);
Console.WriteLine("View Name: {0}, Id: {1}, Items: {2}",view.Name, view.ViewId, view.Items);
return view;
}
static async Task<List<View>> GetViews(Podio client)
{
var views = await client.ViewService.GetViews(APP_ID);
Console.WriteLine("Views: " + views.Count);
foreach (var view in views)
{
Console.WriteLine(" - ({0}) {1}", view.ViewId, view.Name);
}
return views;
}
static async Task<List<Item>> GetViewItems(Podio client, View view)
{
Console.WriteLine("View Items: " + view.Items); // This always return 0
var itemList = new List<Item>();
var itemsRemaining = true;
var offset = 0;
while (itemsRemaining)
{
var colItems = await client.ItemService.FilterItemsByView(appId: APP_ID, viewId: Int32.Parse(view.ViewId), offset: offset);
Console.WriteLine(" Downloaded: {0} to {1}", offset, offset + colItems.Items.Count());
itemList.AddRange(colItems.Items);
offset += colItems.Items.Count();
if (offset >= colItems.Filtered)
{
itemsRemaining = false;
break;
}
}
Console.WriteLine("Total View Items Downloaded: " + itemList.Count);
return itemList;
}
static async Task<Podio> GetClient()
{
var client = new Podio(CLIENT_ID, CLIENT_SECRET);
var auth = await client.AuthenticateWithApp(APP_ID, APP_TOKEN);
Console.WriteLine("Auth expires in: " + auth.ExpiresIn);
return client;
}
}
There are 2 similar methods:
Get Views: https://developers.podio.com/doc/views/get-views-27460
This method is returning items for each view returned
"items": The number of items matching the view
Get View: https://developers.podio.com/doc/views/get-view-27450
This method is not returning items parameter, but you can still get that from groupings param (if there is any grouping). Otherwise - number of items in view is not returned.
"groupings": individual groups data, if grouping is present, otherwise {}
{
"total": total count of items in all groups,
"groups": [{
"count": items count of the single group,
In case if there are no groupings you'll have to call https://developers.podio.com/doc/items/filter-items-by-view-4540284. And then use filtered response value.
"filtered": Total number of items matching the filter,
If you only need number of filtered items - please add limit=1 parameter to your request.
public ActionResult Rajasthan()
{
//List<PackageGallery> all = new List<PackageGallery>();
using (travelAndTourismEntities objentity = new travelAndTourismEntities())
{
List<PackageGallery> all = (from p in objentity.PackageGalleries where p.ParentCategory == "Rajasthan" orderby p.Imageid select p).ToList();
// all = objentity.PackageGalleries.ToList();
return View(all);
}
}
I am writing this query but this is specific to rajasthan only how to make it generalize
You can create a parameter to your action method where you accept the state name you want to use in your filter.
public ActionResult PackageGalleries(string id)
{
var all = new List<PackageGallery>();
using (var db = new travelAndTourismEntities())
{
all = db.PackageGalleries
.Where(s=>s.ParentCategory==id)
.OrderBy(x=>x.ImageId).ToList();
}
return View(all);
}
And you can call it like yourSiteName/yourControllerName/PackageGalleries/rajasthan or yourSiteName/yourControllerName/PackageGalleries/kerala
The last part of the url will be mapped to the id parameter of the action method.
I have a entity record which is shared with or more users. I would like to unshare this record when Deactivate it. I want to do that in Plugin. But I can't understand how to get all users from sharing list who have access to this record. How to do that?
Here is my code snippet:
protected void ExecutePostPersonSetStateDynamicEntity(LocalPluginContext localContext)
{
if (localContext == null)
{
throw new ArgumentNullException("localContext");
}
var context = localContext.PluginExecutionContext;
var targetEntity = (Entity)context.InputParameters["EntityMoniker"];
var state = (OptionSetValue)context.InputParameters["State"];
var columns = new ColumnSet(new[] { "statecode" });
var retrivedEntity = localContext.OrganizationService.Retrieve(targetEntity.LogicalName, targetEntity.Id, columns);
if (state.Value == 1)
{
RevokeAccessRequest revokeRequest = new RevokeAccessRequest()
{
Target = new EntityReference(personEntity.LogicalName, personEntity.Id),
Revokee = new EntityReference(neededEntity.LogicalName, needed.Id)
};
// Execute the request.
}
}
As you can see, I need an entity "neededEntity", I don't know how to get it from "targetEntity" or "retrievedEntity".
You need to use a RetrieveSharedPrincipalsAndAccessRequest
http://msdn.microsoft.com/en-us/library/microsoft.crm.sdk.messages.retrievesharedprincipalsandaccessrequest.aspx
You can start from the included example, basically inside the foreach you call your RevokeAcessRequest
I modified the "Read" operation on my Windows Azure Mobile Services Preview table (named "Item") as follows:
Javascript:
function read(query, user, request)
{
var howRead;
if(howRead == "unique")
{
var sqlUnique = "SELECT DISTINCT ? FROM Item WHERE qProjectCode = ?";
mssql.query(sqlUnique)
request.execute();
}
else if (howRead == "column")
{
var sqlColumn = "SELECT ? FROM Item WHERE qProjectCode = ?";
mssql.query(sqlColumn)
request.execute();
}
else if (howRead == "all")
{
var sqlAll = "SELECT * FROM Item WHERE qProjectCode = ?";
mssql.query(sqlAll)
request.execute();
}
}
This simply species when I want a unique list of a single column's values returned, all items in a single column, or all columns, respectively, all while limiting the read to those records with a given project code.
Right now, this works in C#, but scans the entire table (with other project codes) and always returns all columns. This is inherently inefficient.
c#
var client = new MobileServiceClient("[https path", "[key]");
var table = client.GetTable<Item>();
var query1 = table.Where(w => w.QProjectCode == qgv.projCode && w.QRecord == (int)lbRecord.Items[uStartRecordIndex]);
var query1Enum = await query1.ToEnumerableAsync();
foreach (var i in query1Enum)
{
// process data
}
How do I alter the c# code to deal with the Javascript code? Feel free to critique the overall approach, since I am not a great programmer and can always use advice!
Thanks
A few things:
In your server code, the mssql calls are not doing anything (useful). If you want to get their results, you need to pass a callback (the call is asynchronous) to it.
Most of your scenarios can be accomplished at the client side. The only for which you'll need server code is the one with the DISTINCT modifier.
For that scenario, you'll need to pass a custom parameter to the server script. You can use the WithParameters method in the MobileServiceTableQuery<T> object to define parameters to pass to the service.
Assuming this data class:
public class Item
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Other { get; set; }
public string ProjectCode { get; set; }
}
The code below can be used to accomplish the scenarios 2 and 3 at the client side only (no script needed at the server side). The other one will need some script, which I'll cover later.
Task<IEnumerable<string>> ReadingByColumn(IMobileServiceTable<Item> table, string projectCode)
{
return table
.Where(i => i.ProjectCode == projectCode)
.Select(i => i.Name)
.ToEnumerableAsync();
}
Task<IEnumerable<Item>> ReadingAll(IMobileServiceTable<Item> table, string projectCode)
{
return table.Where(i => i.ProjectCode == projectCode).ToEnumerableAsync();
}
Task<IEnumerable<string>> ReadingByColumnUnique(IMobileServiceTable<Item> table, string projectCode)
{
var dict = new Dictionary<string, string>
{
{ "howRead", "unique" },
{ "projectCode", projectCode },
{ "column", "Name" },
};
return table
.Select(i => i.Name)
.WithParameters(dict)
.ToEnumerableAsync();
}
Now, to support the last method (which takes the parameters, we'll need to do this on the server script:
function read(query, user, request)
{
var howRead = request.parameters.howRead;
if (howRead) {
if (howRead === 'unique') {
var column = request.parameters.column; // WARNING: CHECK FOR SQL INJECTION HERE!!! DO NOT USE THIS IN PRODUCTION!!!
var sqlUnique = 'SELECT DISTINCT ' + column + ' FROM Item WHERE ProjectCode = ?';
mssql.query(sqlUnique, [request.parameters.projectCode], {
success: function(distinctColumns) {
var results = distinctColumns.map(function(item) {
var result = [];
result[column] = item; // mapping to the object shape
return result;
});
request.respond(statusCodes.OK, results);
}
});
} else {
request.respond(statusCodes.BAD_REQUEST, {error: 'Script does not support option ' + howRead});
}
} else {
// no server-side action needed
request.execute();
}
}
I have a custom sitecore button which changes the template of the current item, simple enough.
However as part of this I'm trying to also migrate the renderings of the old layout to a new layout if it's of a certain sublayout type by ItemId. However the ItemId that is returned is always null, the only value I get back from the RenderingDefinition is the UniqueId.
What am I doing wrong?
I have used this blog post as a guide.
The Code
public class ConvertToNewTemplateCommand : Command
{
protected void Run(ClientPipelineArgs args)
{
if (!SheerResponse.CheckModified())
return;
Item item = Context.ContentDatabase.Items[args.Parameters["id"]];
if (args.IsPostBack)
{
if (args.Result == "yes")
{
//Get current layout details
var originalLayoutXml = item[FieldIDs.LayoutField];
//Get new template
TemplateItem hubTemplate = Context.ContentDatabase.GetTemplate("some guid...");
//Change template
item.ChangeTemplate(hubTemplate);
//Reset laytout
ResetLayout(item);
//Get reset layout
var newLayoutXml = item[FieldIDs.LayoutField];
//Add all the module containers to the new layout in the central column
MoveModuleContainers(item, originalLayoutXml, newLayoutXml);
}
}
}
private void MoveModuleContainers(Item item, string oldXml, string newXml)
{
var oldLayout = LayoutDefinition.Parse(oldXml);
var newLayout = LayoutDefinition.Parse(newXml);
bool updated = false;
var oldRenderings = (oldLayout.Devices[0] as DeviceDefinition).Renderings;
var newRenderings = (newLayout.Devices[0] as DeviceDefinition).Renderings;
foreach (RenderingDefinition rendering in oldRenderings)
{
// Here is where the rendering.ItemID is always null
if (rendering != null && !String.IsNullOrEmpty(rendering.ItemID) && new Guid(rendering.ItemID) == new Guid("matching guid..."))
{
rendering.Placeholder = "middlecolumn";
newRenderings.Add(rendering);
updated = true;
}
}
if (updated)
{
// Save item...
}
}
}
I got onto Sitecore support in the end which informed me that I should use:
Sitecore.Data.Fields.LayoutField.GetFieldValue(item.Fields[Sitecore.FieldIDs.LayoutField])
instead of:
item[FieldIDs.LayoutField]
to get the items layoutField correctly. This results in the rendering values being parsed correctly and as they say the rest is history.