Modified table value - axapta

I want to create condition that check other table field in same datasource before modify/update table data.
For example I have table student, field in that table is "status", "name" and "score". Status is enum type and default is "not allow". User can change status field using data grid form.
I want to create condition that Status can change to "allow" if score > 50 else it can't be change. Thanks

As Jan already wrote, one way to solve this would be to overwrite the validateField method of your student table. This method is called every time a field of the table is changed by the user in the form of the table. In the method you could write some code to handle changes to the Status field like e.g.
public boolean validateField(FieldId _fieldId)
{
boolean ret;
ret = super();
switch (_fieldId)
{
case fieldNum(MyStudentTable, Status):
if (this.Status == MyStatus::Allow
&& this.Score <= 50)
{
ret = checkFailed("Score must be greater than 50 to Change the Status."); // TODO create a label
}
break;
}
return ret;
}

What about using validation?
Using validateField or validateWrite on the table or datasource you can test whether the chosen value is valid.
Also the validate method on the datasource or control could be used.
Search the Tables or Forms node of the AOT for thousands of examples.
This answer applies to most "check the value of an entered field".

Related

Datasource Paging Issue (Revised Again)

See Datasource Paging Issue (Revised)
for the original question.
Markus, you were kind enough to help with out with the issue of incorporating a record count into a query using a calculated datasource. I have a search form with 15 widgets - a mix of date ranges, dropdowns, text values and ._contains, ._equals, ._greaterThanOrEquals, ._lessThanOrEquals, etc.
I have tested this extensively against mySQL SQL code and it works fine.
I have now added a 16th parameter PropertyNames, which is a list with binding #datasource.query.filters.Property.PropertyName._in and Options blank. The widget on the form is hidden because it is only used for additional filtering.
Logic such as the following is used, such that a particular logged-in user can only view their own properties. So if they perform a search and the Property is not specified we do:-
if (params.param_Property === null && canViewAllRecords === false) {
console.log(params.param_PropertyNames); // correct output
ds.filters.Property.PropertyName._in = params.param_PropertyNames;
}
The record count (records.length) is correct, and if I for loop through the array of records the record set is correct.
However, on the results page the table displays a larger resultset which omits the PropertyNames filter. So if I was to search on Status 'Open' (mySQL results 50) and then I add a single value ['Property Name London SW45'] for params.param_PropertyNames the record count is 6, the records array is 6 but the datasource display is 50. So the datasource is not filtering on the property array.
Initially I tried without adding the additional parameter and form widget and just using code such as
if (params.param_Property === null && canViewAllRecords === false) {
console.log(params.param_PropertyNames); // correct output
ds.filters.Property.PropertyName._in = properties; // an array of
properties to filter out
}
But this didn't work, hence the idea of adding a form widget and an additional parameter to the calculated recordcount datasource.
If I inspect at query.parameters then I see:-
"param_Status": "Open",
"param_PropertyNames": ["Property Name London SW45"],
If I inspect query.filters:-
name=param_Status, value=Open
name=param_PropertyNames, value=[]}]}
It looks as though the filter isn't set. Even hard coding
ds.filters.Property.PropertyName._in = ['Property Name London SW45'],
I get the same reuslt.
Have you got any idea what would be causing this issue and what I can do for a workaround ?
Using a server side solution I would suggest editing both your SQL datasource query script (server side) that is supposed to filter by this property list and including the same code in your server side script for your calculated Count datasource. The code would look something like this, not knowing your exact details:
var subquery = app.models.Directory.newQuery();
subquery.filters.PrimaryEmail._equals = Session.getActiveUser().getEmail();
subquery.prefetch.Property._add();
var results = subquery.run();
if(!results[0].CanViewAllRecords) {
query.filters.Property.PropertyName._in = results[0].Property.map(function(i) {return i.PropertyName;});
}
By adding this code you are filtering your directory by your current user and prefetching the Property relation table, then you set the filter only if your user canviewallRecords is false and use JS map function to create an array of the PropertyName field in the Property table. As I stated, your code may not be exactly the same depending on how you have to retrieve your user canviewallrecords property and then of course I don't know your relation between user and Property table either, is it one-to-many or other. But this should give you an idea how to implement this on server side.

How to filter by date and do a Form's query by code?

I have to do a Form query by code. The datasource table is CustomVendTable(is a custom table).
I open a form and in my init method I get the table caller :
public void init ()
{
VendTable = myVendTableCaller;
myVendTableCaller = element.args().record();
// There is a dialog and get a date by a _Dialog_ and save in a date variable
super();
}
In my data source I have a build a query. The table in my datasource is related whit VendTable. I filter by code my DataSource by myVendTableCaller.RecId and variable date dateByDialog inserted in the opening dialog
My query is this:
public void executeQuery()
{
query q = new Query();
QueryBuildRange qbr;
QueryBuildDataSource qbds ;
QueryRun queryRun;
qbds = q.addDataSource(tableNum(CustomVendTable) );
qbds.addRange(fieldNum(CustomVendTable, ValidFrom)).value(SysQuery::value( strFmt ("<=%1 ", _dateByDialog)) ) ;
qbds.addRange(fieldNum(CustomVendTable, ValidTo)).value(SysQuery::value( strFmt (">=%1 ", _dateByDialog))) ;
qbds.addRange(fieldNum(CustomVendTable, Vendor )).value(SysQuery::value(myVendTableCaller.recId));
queryRun = new QueryRun (q);
CustomVendTable_ds.query(queryRun.query());
super();
}
*For information there is a Table Relation CustomVendTable.Vendor == VendTable.RecId
So, I have some problems! I think not to be able to make a correct query by date. The fields ValidFrom - ValidTo are UTCdatetime type.
1) I have to convert my _dateByDialog in UTC ? How to do ? It' s correct my query date way ?
Considering that the conversion is not impossible, my BIG problem is that by filtering by date, if I have only one record with recid same range and dates I can somehow see it, BUT if there are more record with these same characteristics (If I have 2 record) I don't see nothing! My Form Grid is void!
I have read that you should set the Session date time (I'm talking about this ) to have control over dates.
I still believe that I do not build my Query very well.
Do you have an idea how can I do ?
If you used DateTimeUtil::newDateTime and made new UTCDateTime parameters for the dates?
https://community.dynamics.com/ax/b/alirazatechblog/archive/2012/09/03/date-to-utcdatetime-convertion-dynamics-ax-2012
Maybe you use a table which use date effective. You assume you have to do the selection yourself, this is not true.
Instead call method validTimeStateAsOfDate on the datasource. See this answer for details.

Ax2012 - get the value of accountNum in the selected row in a grid

In the form cutslistepage , i want to get the value of accountNum of the selected row in grid and passe it to another form
i have try that :
int64 recordsCount;
recordsCount = CustTable_ds.recordsMarked().lastIndex();
// CustTable = CustTable_ds.getFirst(1);
If you want to retrieve the CustTable record, check the CustTableListPageInteraction class.
In the selectionChanged method, it has the following code:
custTable = CustTable::findRecId(this.listPage().activeRecord(queryDataSourceStr(CustTableListPage, CustTable)).RecId);
This is how you can retrieve the record. But since it is already done, you can simply use the custTable variable that is already declared in the class declaration.
Side note: if you have an other form that is opened from the list page, it should automatically be filtered based on the relations between the data sources of the form. So you might be searching for a solution for a problem you shouldn't have. For example create a form that has a data source with a relation to the CustTable table on it and it should create a dynaink between the list page and your form, filtering the records for that customer.
If only one record is selected you can do:
info(CustTable_ds.accountNum);
Otherwise, if more than one record is selected you need to do something like:
custTable = CustTable_ds.getFirst(true);
while (custTable)
{
info(custTable.accountNum);
custTable = CustTable_ds.getNext();
}

Error with creating record in EF 6 - "Cannot insert explicit value for identity column in table "Photos" when IDENTITY_INSERT is set to OFF"

I recently upgraded my application from ASP.NET MVC 3 and EF 4 to ASP.NET MVC 5 and EF 6. I have several repository functions that I'm using for CRUD functionality.
I haven't changed anything, but I'm suddenly receiving this error if I try to add a record to my entities:
Cannot insert explicit value for identity column in table "Photos" when IDENTITY_INSERT is set to OFF
Here's an example of one of these methods
public void SavePhoto(Photo photo)
{
if (photo.PhotoID == 0) // new photo
_entities.Photos.Add(photo);
else // edit photo
{
_entities.Photos.Attach(photo);
_entities.Entry(photo).State = EntityState.Modified;
}
_entities.SaveChanges();
}
The PhotoID column in my database for this table is set to be the Identity. When this worked before, it would just increment the PhotoID column value based on the last entry (as expected).
Is there a better way to do this now with EF 6?
Is your PhotoId column is "int" type and annotated with "DateGenerated identity"? If so, the following code will error. Because EF might thinking you are inserting 0 into identity column.
if (photo.PhotoID == 0) // new photo
_entities.Photos.Add(photo);
Use id == 0 to check whether it is a new photo or not is not a good practice, actually it is a "bug", because say you have 3 records in the system(which default could mean your photoid is not greater than 4), And somehow you PhotoID was manipulated as 100 in the backend, now when your code run, your code will set its state as Modified. And EF might throw error for you, or EF might try to insert it for you instead of editing.
So I would suggest to use follow code
var photo = _entities.Photos.Find(photo.PhotoId)
if (photo == null) {
//your code to add photo
}
else
{
//your code to set the the modal state to modified.
}

How to filter language field in Dynamics AX?

I'm trying to filter the table by the field "LanguageId" to show only "fr".
I made a new method in my form datasource
Here is my code
public void filtr()
{
DirPartyTable _dirPartyTable;
select LanguageId from _dirPartytable
where _dirPartyTable.LanguageId == "fr";
}
When running this code nothing happens.
How to invoke it to work?
You can overwrite the init method of the DirPartyTable datasource and add this code to add a range on languageId with value "fr":
SysQuery::findOrCreateRange(this.query().dataSourceTable(tableNum(DirPartyTable)), fieldNum(DirPartyTable, LanguageId)).value("fr");

Resources