Synchronization Issue with Customizing an Integration with Microsoft Dataverse - dynamics-business-central

followed documentation : https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/administration/administration-custom-cds-integration docs and https://yzhums.com/17065/
When I launch “Run Full Sync.” and look at the job log of my testing table, only records initially created in business central are inserted in the crm. Any rows that I created from my integration table in the crm are not inserted in business central.
I suspect that this note below may be the cause because some columns were skipped during the creation of the proxy table using AL Table Proxy Generator butI have no way to know since no error messages are showing up regarding that.
https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/devenv-al-table-proxy-generator
Example
Let's say I have 2 records in my testing table on the crm side.
I can see them in my proxy Table List on the business central side, but they are not inserted yet in my target table.
Note for the first screen shot: If I select one of those two rows in my proxy testing table and click on create in business central, it creates it successfully in bc... so I'm wondering why that is working and not the "run full sync"
Then I create a record from bc before running the full synchronization and look at the results.
We can see here that one record was inserted from BC to the crm (all fields were mapped correctly) but nothing from the crm to BC.
Here's my project folder tree. If you need to see a specific page let me know.
CODE
Tab50100.Testingtableforintegration.al
table 50100 "Testing table for integration"
{
Caption = 'Target integration table';
DataClassification = ToBeClassified;
fields
{
field(1; "name"; Code[25])
{
Caption = 'name';
DataClassification = ToBeClassified;
}
field(2; "my bc field one"; Text[50])
{
Caption = 'my bc field one';
DataClassification = ToBeClassified;
}
field(3; "my bc field two"; Integer)
{
Caption = 'my bc field two';
DataClassification = ToBeClassified;
}
}
keys
{
key(PK; "name")
{
Clustered = true;
}
}
}
Pag50101.TestingIntrecordslist.al
page 50101 "target table records list"
{
ApplicationArea = All;
Caption = 'target table records list';
PageType = List;
SourceTable = "Testing table for integration";
UsageCategory = Lists;
CardPageId = "target table Card";
Editable = false;
layout
{
area(content)
{
repeater(General)
{
field("code"; Rec."name")
{
ApplicationArea = All;
ToolTip = 'Specifies the value of the code field.';
}
field("my bc field two"; Rec."my bc field two")
{
ApplicationArea = All;
ToolTip = 'Specifies the value of the my bc field two field.';
}
field("my bc field one"; Rec."my bc field one")
{
ApplicationArea = All;
ToolTip = 'Specifies the value of the my bc field one field.';
}
field(SystemCreatedAt; Rec.SystemCreatedAt)
{
ApplicationArea = All;
ToolTip = 'Specifies the value of the SystemCreatedAt field.';
}
field(SystemCreatedBy; Rec.SystemCreatedBy)
{
ApplicationArea = All;
ToolTip = 'Specifies the value of the SystemCreatedBy field.';
}
}
}
}
actions
{
area(Processing)
{
group(ActionGroupCDS)
{
Caption = 'Dataverse';
Visible = CDSIntegrationEnabled;
action(CDSGotoTargetRecord)
{
Caption = 'Go to Dataverse record';
ApplicationArea = All;
Visible = true;
Image = CoupledCustomer;
Enabled = CDSIsCoupledToRecord;
ToolTip = 'Open the coupled Dataverse Record';
trigger OnAction()
var
CRMIntegrationManagement: Codeunit "CRM Integration Management";
begin
CRMIntegrationManagement.ShowCRMEntityFromRecordID(Rec.RecordId);
end;
}
action(CDSSynchronizeNow)
{
Caption = 'Synchronize';
ApplicationArea = All;
Visible = true;
Image = Refresh;
Enabled = CDSIsCoupledToRecord;
ToolTip = 'Send or get updated data to or from Microsoft Dataverse.';
trigger OnAction()
var
CRMIntegrationManagement: Codeunit "CRM Integration Management";
begin
CRMIntegrationManagement.UpdateOneNow(Rec.RecordId);
end;
}
action(ShowLog)
{
Caption = 'Synchronization Log';
ApplicationArea = All;
Visible = true;
Image = Log;
ToolTip = 'View integration synchronization jobs for the customer table.';
trigger OnAction()
var
CRMIntegrationManagement: Codeunit "CRM Integration Management";
begin
CRMIntegrationManagement.ShowLog(Rec.RecordId);
end;
}
group(Coupling)
{
Caption = 'Coupling';
Image = LinkAccount;
ToolTip = 'Create, change, or delete a coupling between the Business Central record and a Microsoft Dataverse row.';
action(ManageCDSCoupling)
{
Caption = 'Set Up Coupling';
ApplicationArea = All;
Visible = true;
Image = LinkAccount;
ToolTip = 'Create or modify the coupling to a Microsoft Dataverse Record';
trigger OnAction()
var
CRMIntegrationManagement: Codeunit "CRM Integration Management";
begin
CRMIntegrationManagement.DefineCoupling(Rec.RecordId);
end;
}
action(DeleteCDSCoupling)
{
Caption = 'Delete Coupling';
ApplicationArea = All;
Visible = true;
Image = UnLinkAccount;
Enabled = CDSIsCoupledToRecord;
ToolTip = 'Delete the coupling to a Microsoft Dataverse Record';
trigger OnAction()
var
CRMCouplingManagement: Codeunit "CRM Coupling Management";
begin
CRMCouplingManagement.RemoveCoupling(Rec.RecordId);
end;
}
}
}
}
}
trigger OnOpenPage()
begin
CDSIntegrationEnabled := CRMIntegrationManagement.IsCDSIntegrationEnabled();
end;
trigger OnAfterGetCurrRecord()
begin
if CDSIntegrationEnabled then
CDSIsCoupledToRecord := CRMCouplingManagement.IsRecordCoupledToCRM(Rec.RecordId);
end;
var
CRMIntegrationManagement: Codeunit "CRM Integration Management";
CRMCouplingManagement: Codeunit "CRM Coupling Management";
CDSIntegrationEnabled: Boolean;
CDSIsCoupledToRecord: Boolean;
}
Pag50100.TestingIntegrationCard.al
page 50100 "target table Card"
{
Caption = 'target table Card';
PageType = Card;
SourceTable = "Testing table for integration";
layout
{
area(content)
{
group(General)
{
field("code"; Rec."name")
{
ApplicationArea = All;
ToolTip = 'Specifies the value of the code field.';
}
field("my bc field one"; Rec."my bc field one")
{
ApplicationArea = All;
ToolTip = 'Specifies the value of the my bc field one field.';
}
field("my bc field two"; Rec."my bc field two")
{
ApplicationArea = All;
ToolTip = 'Specifies the value of the my bc field two field.';
}
field(SystemCreatedAt; Rec.SystemCreatedAt)
{
ApplicationArea = All;
ToolTip = 'Specifies the value of the SystemCreatedAt field.';
}
field(SystemCreatedBy; Rec.SystemCreatedBy)
{
ApplicationArea = All;
ToolTip = 'Specifies the value of the SystemCreatedBy field.';
}
field(SystemId; Rec.SystemId)
{
ApplicationArea = All;
ToolTip = 'Specifies the value of the SystemId field.';
}
}
}
}
}
Generated Proxy Table.al
table 50101 "CDS cr46d_d365salestestingtableforbcintegration"
{
ExternalName = 'cr46d_d365salestestingtableforbcintegration';
TableType = CDS;
Description = '';
fields
{
field(1; cr46d_D365SalestestingtableforbcintegrationId; GUID)
{
ExternalName = 'cr46d_d365salestestingtableforbcintegrationid';
ExternalType = 'Uniqueidentifier';
ExternalAccess = Insert;
Description = 'Unique identifier for entity instances';
Caption = 'D365 Sales testing table for bc integration';
}
field(2; CreatedOn; Datetime)
{
ExternalName = 'createdon';
ExternalType = 'DateTime';
ExternalAccess = Read;
Description = 'Date and time when the record was created.';
Caption = 'Created On';
}
field(4; ModifiedOn; Datetime)
{
ExternalName = 'modifiedon';
ExternalType = 'DateTime';
ExternalAccess = Read;
Description = 'Date and time when the record was modified.';
Caption = 'Modified On';
}
field(25; statecode; Option)
{
ExternalName = 'statecode';
ExternalType = 'State';
ExternalAccess = Modify;
Description = 'Status of the D365 Sales testing table for bc integration';
Caption = 'Status';
InitValue = " ";
OptionMembers = " ",Active,Inactive;
OptionOrdinalValues = -1, 0, 1;
}
field(27; statuscode; Option)
{
ExternalName = 'statuscode';
ExternalType = 'Status';
Description = 'Reason for the status of the D365 Sales testing table for bc integration';
Caption = 'Status Reason';
InitValue = " ";
OptionMembers = " ",Active,Inactive;
OptionOrdinalValues = -1, 1, 2;
}
field(29; VersionNumber; BigInteger)
{
ExternalName = 'versionnumber';
ExternalType = 'BigInt';
ExternalAccess = Read;
Description = 'Version Number';
Caption = 'Version Number';
}
field(30; ImportSequenceNumber; Integer)
{
ExternalName = 'importsequencenumber';
ExternalType = 'Integer';
ExternalAccess = Insert;
Description = 'Sequence number of the import that created this record.';
Caption = 'Import Sequence Number';
}
field(31; OverriddenCreatedOn; Date)
{
ExternalName = 'overriddencreatedon';
ExternalType = 'DateTime';
ExternalAccess = Insert;
Description = 'Date and time that the record was migrated.';
Caption = 'Record Created On';
}
field(32; TimeZoneRuleVersionNumber; Integer)
{
ExternalName = 'timezoneruleversionnumber';
ExternalType = 'Integer';
Description = 'For internal use only.';
Caption = 'Time Zone Rule Version Number';
}
field(33; UTCConversionTimeZoneCode; Integer)
{
ExternalName = 'utcconversiontimezonecode';
ExternalType = 'Integer';
Description = 'Time zone code that was in use when the record was created.';
Caption = 'UTC Conversion Time Zone Code';
}
field(34; cr46d_Name; Text[100])
{
ExternalName = 'cr46d_name';
ExternalType = 'String';
Description = '';
Caption = 'Name';
}
field(35; cr46d_mytestingcolumnone; Text[100])
{
ExternalName = 'cr46d_mytestingcolumnone';
ExternalType = 'String';
Description = '';
Caption = 'my testing column one';
}
field(36; cr46d_mytestingcolumntwo; Integer)
{
ExternalName = 'cr46d_mytestingcolumntwo';
ExternalType = 'Integer';
Description = '';
Caption = 'my testing column two';
}
field(37; cr46d_CoupledtoCRM; Boolean)
{
ExternalName = 'cr46d_coupledtocrm';
ExternalType = 'Boolean';
Description = '';
Caption = 'Coupled to CRM';
}
}
keys
{
key(PK; cr46d_D365SalestestingtableforbcintegrationId)
{
Clustered = true;
}
key(Name; cr46d_Name)
{
}
}
fieldgroups
{
fieldgroup(DropDown; cr46d_Name)
{
}
}
}
Pag50102.ProxyTableList.al
// List of records of the proxy table that shows us the records imported from Dynamics Sales CRM
// each table we want to import need to have its corresponding proxy table. Even the default tables like contact has its proxy tablke that have been automaticaly created by the connection setup.
page 50102 "Proxy Table List"
{
ApplicationArea = All;
Caption = 'Proxy testing Table - Dataverse';
PageType = List;
SourceTable = "CDS cr46d_d365salestestingtableforbcintegration";
UsageCategory = Lists;
layout
{
area(content)
{
repeater(General)
{
field(cr46d_Name; Rec.cr46d_Name)
{
ApplicationArea = All;
ToolTip = 'Specifies the value of the Name field.';
}
field(cr46d_mytestingcolumnone; Rec.cr46d_mytestingcolumnone)
{
ApplicationArea = All;
ToolTip = 'Specifies the value of the my testing column one field.';
}
field(cr46d_mytestingcolumntwo; Rec.cr46d_mytestingcolumntwo)
{
ApplicationArea = All;
ToolTip = 'Specifies the value of the my testing column two field.';
}
field(cr46d_D365SalestestingtableforbcintegrationId; Rec.cr46d_D365SalestestingtableforbcintegrationId)
{
ApplicationArea = All;
ToolTip = 'Specifies the value of the D365 Sales testing table for bc integration field.';
}
}
}
}
actions
{
area(processing)
{
action(CreateFromCDS)
{
ApplicationArea = All;
Caption = 'Create in Business Central';
Promoted = true;
PromotedCategory = Process;
ToolTip = 'Generate the record from the coupled Microsoft Dataverse row.';
Image = AssemblyBOM;
trigger OnAction()
var
// initialise proxy table variable and CRMIntegrationManagement code unit
ProxyTable: Record "CDS cr46d_d365salestestingtableforbcintegration";
CRMIntegrationManagement: Codeunit "CRM Integration Management";
begin
// apply the actual current page filter (selected record) on the proxy table records and pass it to the
// CreateNewRecordsFromCRM function for insertion in the target table
CurrPage.SetSelectionFilter(ProxyTable);
CRMIntegrationManagement.CreateNewRecordsFromCRM(ProxyTable);
end;
}
}
}
var
CurrentlyCoupledProxyTable: Record "CDS cr46d_d365salestestingtableforbcintegration";
// is launched before the startup of the page and calls the OnRun() function of codeunit 5330 "CRM Integration Management", which then
// execute CheckOrEnableCRMConnection to establish the connection with dataverse.
trigger OnInit()
begin
Codeunit.Run(Codeunit::"CRM Integration Management");
end;
// this function is used by the codeunit dataverse event
procedure SetCurrentlyCoupledProxyTable(ProxyTable: Record "CDS cr46d_d365salestestingtableforbcintegration")
begin
CurrentlyCoupledProxyTable := ProxyTable;
end;
}
Cod50100.DataverseEvent.al
// note to read comments: entry here means a line in a table or a single record.
// documentation: https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/administration/administration-custom-cds-integration
codeunit 50100 DataverseEvent
{
// in the codeunit CRM Setup Defaults, when the procedure OnGetCDSTableNo is called, execute this local procedure.
// launched when button setup couplings in BC is clicked
[EventSubscriber(ObjectType::Codeunit, Codeunit::"CRM Setup Defaults", 'OnGetCDSTableNo', '', false, false)]
local procedure HandleOnGetCDSTableNo(BCTableNo: Integer; var CDSTableNo: Integer; var handled: Boolean)
begin
// error('HandleOnGetCDSTableNo was called! %1', BCTableNo);
// specify to the function OnGetCDSTableNo to exit immediatly due to handled := true because BCTableNo and CDSTableNo
// are not default BC tables and will not be found in the codeunit CRM Setup Defaults. (For more details see codeunit 5334)
if BCTableNo = DATABASE::"Testing table for integration" then begin
CDSTableNo := DATABASE::"CDS cr46d_d365salestestingtableforbcintegration";
handled := true; // handled means here taken care of by us.
end;
end;
[EventSubscriber(ObjectType::Codeunit, Codeunit::"Lookup CRM Tables", 'OnLookupCRMTables', '', true, true)]
local procedure HandleOnLookupCRMTables(CRMTableID: Integer; NAVTableId: Integer; SavedCRMId: Guid; var CRMId: Guid; IntTableFilter: Text; var Handled: Boolean)
begin
if CRMTableID = Database::"CDS cr46d_d365salestestingtableforbcintegration" then
Handled := LookupProxyTable(SavedCRMId, CRMId, IntTableFilter); // this will return true if CRMID point to a proxy table entry.
end;
// this function returns a boolean used to assign Handled var in HandleOnLookupCRMTables
// the goal of this function is to replicate the procedure LookupCRM<tableName>(we can find the definitions of those functions in the codeunit 5332 - Lookup CRM Tables)
// as if we were to add it directly (but we can't because microsoft don't want their code touched, that is why they specified a event trigger that we can use to extend their codeunit)
local procedure LookupProxyTable(SavedCRMId: Guid; var CRMId: Guid; IntTableFilter: Text): Boolean
var
ProxyTable: Record "CDS cr46d_d365salestestingtableforbcintegration"; // the proxy table
OriginalProxyTable: Record "CDS cr46d_d365salestestingtableforbcintegration";
OriginalProxyTableList: Page "Proxy Table List"; // THIS IS A LIST NOT A CARD
begin
if not IsNullGuid(CRMId) then begin // if the crm id is not null. The crm id represents the id of an entry in the proxy table
if ProxyTable.Get(CRMId) then // if the proxy table contains the entry linked with the crm id
OriginalProxyTableList.SetRecord(ProxyTable); // Set the proxy table list to the proxy table that has been filtrated by the passed crm id
if not IsNullGuid(SavedCRMId) then// ????
if OriginalProxyTable.Get(SavedCRMId) then begin
Message('we are here in LookupProxyTable');
OriginalProxyTableList.SetCurrentlyCoupledProxyTable(OriginalProxyTable);
end;
;
// gives to the list the currently coupled proxy table
// OriginalProxyTableList.SetCurrentlyCoupledProxyTable(OriginalProxyTable);
end;
ProxyTable.SetView(IntTableFilter);
OriginalProxyTableList.SetTableView(ProxyTable);
OriginalProxyTableList.LookupMode(true);
if OriginalProxyTableList.RunModal = ACTION::LookupOK then begin
OriginalProxyTableList.GetRecord(ProxyTable);
CRMId := ProxyTable.cr46d_D365SalestestingtableforbcintegrationId;
exit(true);
end;
exit(false);
end;
[EventSubscriber(ObjectType::Codeunit, Codeunit::"CRM Setup Defaults", 'OnAddEntityTableMapping', '', true, true)]
local procedure HandleOnAddEntityTableMapping(var TempNameValueBuffer: Record "Name/Value Buffer" temporary);
var
CRMSetupDefaults: Codeunit "CRM Setup Defaults";
begin
CRMSetupDefaults.AddEntityTableMapping('cr46d_d365salestestingtableforbcintegration', DATABASE::"CDS cr4', DATABASE::"Testing table for integration", TempNameValueBuffer); //IMPORTANT TO CHANGE - LOGICAL NAME OF THE DV TABLE
CRMSetupDefaults.AddEntityTableMapping('cr46d_d365salestestingtableforbcintegration', DATABASE::"CDS cr46d_d365salestestingtableforbcintegration", TempNameValueBuffer);
end;
local procedure InsertIntegrationTableMapping(var IntegrationTableMapping: Record "Integration Table Mapping"; MappingName: Code[20]; TableNo: Integer; IntegrationTableNo: Integer; IntegrationTableUIDFieldNo: Integer; IntegrationTableModifiedFieldNo: Integer; TableConfigTemplateCode: Code[10]; IntegrationTableConfigTemplateCode: Code[10]; SynchOnlyCoupledRecords: Boolean)
begin
IntegrationTableMapping.CreateRecord(MappingName, TableNo, IntegrationTableNo, IntegrationTableUIDFieldNo, IntegrationTableModifiedFieldNo, TableConfigTemplateCode, IntegrationTableConfigTemplateCode, SynchOnlyCoupledRecords, IntegrationTableMapping.Direction::Bidirectional, 'CDS');
end;
procedure InsertIntegrationFieldMapping(IntegrationTableMappingName: Code[20]; TableFieldNo: Integer; IntegrationTableFieldNo: Integer; SynchDirection: Option; ConstValue: Text; ValidateField: Boolean; ValidateIntegrationTableField: Boolean)
var
IntegrationFieldMapping: Record "Integration Field Mapping";
begin
IntegrationFieldMapping.CreateRecord(IntegrationTableMappingName, TableFieldNo, IntegrationTableFieldNo, SynchDirection,
ConstValue, ValidateField, ValidateIntegrationTableField);
end;
[EventSubscriber(ObjectType::Codeunit, Codeunit::"CDS Setup Defaults", 'OnAfterResetConfiguration', '', true, true)]
local procedure HandleOnAfterResetConfiguration(CDSConnectionSetup: Record "CDS Connection Setup")
var
IntegrationTableMapping: Record "Integration Table Mapping";
IntegrationFieldMapping: Record "Integration Field Mapping";
ProxyTable: Record "CDS cr46d_d365salestestingtableforbcintegration";
TargetTable: Record "Testing table for integration";
begin
// inserts a line in the integrationTableMapping
InsertIntegrationTableMapping(
IntegrationTableMapping, 'My testing table',
DATABASE::"Testing table for integration", DATABASE::"CDS cr46d_d365salestestingtableforbcintegration", ProxyTable.FieldNo(cr46d_D365SalestestingtableforbcintegrationId), ProxyTable.FieldNo(ModifiedOn), '', '', true);
// in the newly insertion, insert integration fields to couple
InsertIntegrationFieldMapping('My testing table', TargetTable.FieldNo("name"), ProxyTable.FieldNo(cr46d_name), IntegrationFieldMapping.Direction::Bidirectional, '', true, false);
InsertIntegrationFieldMapping('My testing table', TargetTable.FieldNo("my bc field one"), ProxyTable.FieldNo(cr46d_mytestingcolumnone), IntegrationFieldMapping.Direction::Bidirectional, '', true, false);
InsertIntegrationFieldMapping('My testing table', TargetTable.FieldNo("my bc field two"), ProxyTable.FieldNo(cr46d_mytestingcolumntwo), IntegrationFieldMapping.Direction::Bidirectional, '', true, false);
end;
}
So I would like to know first of all what is causing the synchronization to malfunction without raising any messages & how to solve it step by step/in detail if modifications are needed in the project code itself. Hope this was clear enough to illustrate my issue, if any additional clarifications are needed please let me know.
Thank you very much!

I solved my Issue, my proxy table was missing the field modified by from Dataverse. You can see the error message in the job queue entries.

Related

I'm trying to write some test with firstore and swiftui, I can create and read, but now i don't know how to list unique data,

You can see I have two fields in this document, "ing01", and "nameReceta" every document in this collection has the same name fields, in the field "ing01" I have "Pimienta" in description, my app it allows more documents whit "Pimienta" in "ing01" and this is fine, but when I want to list it I need list only one "Pimienta", how can I remove the others?
I have this data model
struct ModeloRecetasIng : Identifiable, Hashable, Equatable {
var id: String
var nameReceta: String
var ing01: String
}
and here I get the data, and it works fine.
class ingredientesAdd : ObservableObject {
// #Published var datosNoDupl = [DataNoDuplicates]()
#Published var datas = [ModeloRecetasIng]()
init() {
// Borra el cache
let settings = FirestoreSettings()
settings.isPersistenceEnabled = false
let db = Firestore.firestore()
db.settings = settings
// Borra el cache
db.collection("DespensaIng01").getDocuments { (snap, err) in
if err != nil {
print((err?.localizedDescription)!)
return
}
for i in snap!.documents
{
let id = i.documentID
let nameReceta = i.get("nameReceta") as! String
let ing01 = i.get("ing01") as! String
//
self.datas.append(ModeloRecetasIng(id: id, nameReceta: nameReceta, ing01: ing01))
}
// I'm trying to use set but it doesn't work
let uniqueUnordered = Array(Set(self.datas))
self.datas = uniqueUnordered
print(self.datas)
}
}
}
When I get my Print I see this
Pimienta
Pimienta
Zanahoria
Zanahoria
Zanahoria
and I only want this
Pimienta
Zanahoria
Solved.. just using a custom ID in firestore, and no more duplicates and now i need to sum de quantity only

Trying to understand sorting in the Table widget for a Page

I am trying to understand how sorting works in Table widgets works when loading a page. For most of my pages using the Table widget, the page loads sorted by the first column.
I do see the below code in the onAttach event for the Table panel in a page. I am wondering if this is the code that sets the sorting when a page loads.
// GENERATED CODE: modify at your own risk
window._am = window._am || {};
if (!window._am.TableState) {
window._am.TableState = {};
window._am.inFlight = false;
}
if (!window._am.sortTableBy) {
window._am.sortTableBy = function(datasource, field, fieldHeader, tableState) {
if (!field) {
throw "Can't sort the table because specified field was not found.";
}
tableState.inFlight = true;
if (tableState.sortByField === field.name) {
tableState.ascending = !tableState.ascending;
} else {
if (tableState.fieldHeader) {
tableState.fieldHeader.text = tableState.fieldHeaderText;
tableState.fieldHeader.ariaLabel = "";
}
tableState.sortByField = field.name;
tableState.ascending = true;
tableState.fieldHeader = fieldHeader;
tableState.fieldHeaderText = fieldHeader.text;
}
datasource.query.clearSorting();
var sortDirection = tableState.ascending ? "ascending" : "descending";
datasource.query.sorting[field.name]["_" + sortDirection]();
datasource.query.pageIndex = 1;
datasource.load(function() {
tableState.inFlight = false;
fieldHeader.text = fieldHeader.text.replace(/ (\u25B2|\u25BC)/g, "");
if (tableState.sortByField === field.name) {
fieldHeader.ariaLabel = fieldHeader.text + " sort " + sortDirection;
fieldHeader.text = fieldHeader.text + (tableState.ascending ? " \u25B2" : " \u25BC");
app.accessibility.announce(fieldHeader.ariaLabel);
}
});
};
}
Sorting is set on your datasource.
Click the model (top left) that your table is using.
Click Datasources and expand your Datasource (there will only be one, unless you have created additional ones).
Once you choose the field you want the table to use for sorting, you can choose "Ascending" or "Descending".
The problem is with adding new records from a separate create form. The new records always appear at the end of the list , until a subsequent 'load' is performed.

Additional Datasource with Difference Table Name

I have a domain called Test that has been running look-up SQL queries to select from another database.
I want to get away from this implementation and goto multiple datasource support of Grails 2.0. However, the table name in the other database is a called Panel.
Is it possible to map the domain to the alternative database and also map which table it selects from?
// Datasource.groovy
development {
dataSource {
dbCreate = 'create-drop' // one of 'create', 'create-drop','update'
url = "jdbc:sqlserver://machine\\SQLEXPRESS;databaseName=primarydb"
username = "user"
password = "password"
}
dataSource_otherdb {
url = "jdbc:sqlserver://remoteserver:1433;databaseName=otherdb"
}
}
// Test.groovy
class Test {
String name
int key
String abbreviation
boolean active = true
static mapping = {
sort name: "asc"
datasource("otherdb")
}
}
There is a "table"configuration in mapping closure for that.
// Test.groovy
class Test {
String name
int key
String abbreviation
boolean active = true
static mapping = {
table 'Panel' //customize table name
sort name: "asc"
datasource("otherdb")
}
}

Updating a foreign key to Null value using nhibernate

I have two table BuildGroup and table DocumentTemplate. DocumentTemplate table has BuildGroupId as foreign key which is nullable. In a certain senario I update BuildGroupId in DocumentTemplate table.
public bool EditDocTempForBldGrp(int docId, int bldGrpId)
{
try
{
using (ISession session = Document.OpenSession())
{
using (ITransaction transaction = session.BeginTransaction())
{
HSDocumentTemplate objDocBO = new HSDocumentTemplate();
objDocBO = GetDocumentDetailsById(docId);
HSBuildGroup objBldGrp = new HSBuildGroup();
if (bldGrpId != 0)
{
objBldGrp.Id = bldGrpId;
}
else
{
//int ? bldid = null;
//objDocBO.HSBuildGroup.Id = null;
//objDocBO.HSBuildGroup.Id = DBNull.Value;
//objDocBO.HSBuildGroup.Id = -1;
}
objDocBO.HSBuildGroup = objBldGrp;
session.Update(objDocBO);
transaction.Commit();
}
}
return true;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return false;
}
}
In another senario I need to set BuildGroupId in DocumentTemplate table again to
dbnull.value. I tried with different cases as in else block. It giving the error : Cannot
implicitly convert type 'System.DBNull' to 'int'.
How can I update a foreign key value with NULL? Any help will be appreciated.
A few observations:
You should not assign the Id to a HSBuildGroup object, but instead load the instance via Session.Load() in case the bldGrpId is not 0.
You can just set the build group of a document to null like this:
objDocBO.HSBuildGroup = null;
NHibernate will take care of the rest.
Hope that helps.
Use Session.Load and null as Kay Herzam said.
You must to be sure than the document exist to call session.Load. Example:
public bool EditDocTempForBldGrp(int docId, int bldGrpId)
{
try
{
using (ISession session = Document.OpenSession())
using (ITransaction transaction = session.BeginTransaction())
{
session.Get<HSDocumentTemplate>(docId).HSBuildGroup
= bldGrpId = 0 ? null : session.Load<HSBuildGroup>(bldGrpId);
transaction.Commit();
}
}
}
This way nhibernate will execute something like,
select ... from DocumentTemplate where DocId = ..;
UPDATE DocumentTemplate SET .... , BuildGroupId = null where DocumentId = XX;
or
select ... from DocumentTemplate where DocId = ..;
UPDATE DocumentTemplate SET .... , BuildGroupId = YY where DocumentId = XX;
Note there is no select for BuildGroup to the database.
If you are not sure about the existence of the build group, your code should look like:
public bool EditDocTempForBldGrp(int docId, int bldGrpId)
{
try
{
using (ISession session = Document.OpenSession())
using (ITransaction transaction = session.BeginTransaction())
{
session.Get<HSDocumentTemplate>(docId).HSBuildGroup
= session.Get<HSBuildGroup>(bldGrpId);
transaction.Commit();
}
}
}
This way nhibernate will execute something like,
select ... from DocumentTemplate where DocId = ..;
SELECT .... FROM BuildGroup where buildgroupid = ZZ;
UPDATE DocumentTemplate SET .... , BuildGroupId = null where DocumentId = XX;
Get automatically returns null if the object doesn't exist.
Finally you don't need to call Session.Update() this is for reattaching an entity. Everything associated to a Session will be flushed when you commit the transaction.

Html strip in asp.net

I have used a ckeditor in which user can submit data to the database in styles but when the data is populated in the datagrid then also it comes with same styles in IE
but I want it to be in plain text when get populated.
the function for populating the data is as follows:
protected void LoadQA(int intQuestionId)
{
string strSelectQuery = "SELECT TITLE, DESCRIPTION, ANSWER, FK_OWNER_ID, CREATED_ON FROM M_QA WHERE PK_ID = "
+ intQuestionId + " AND IS_ACTIVE = 1";
OleDbConnection connectionSelectQuestion = new OleDbConnection(ConfigurationSettings.AppSettings["SQLConnectionString"]);
OleDbCommand commandSelectQuestion = new OleDbCommand(strSelectQuery, connectionSelectQuestion);
OleDbDataReader readerSelectQuestion;
try
{
connectionSelectQuestion.Open();
readerSelectQuestion = commandSelectQuestion.ExecuteReader();
if (readerSelectQuestion.Read())
{
lblHeader.Text = "View Q&A";
txtTitle.Text = readerSelectQuestion["TITLE"].ToString();
if (readerSelectQuestion["TITLE"].ToString().Length > 50)
{
ViewState["QA_Title"] = readerSelectQuestion["TITLE"].ToString().Substring(0, 50) + "...";
}
else
{
ViewState["QA_Title"] = readerSelectQuestion["TITLE"].ToString();
}
txtDescription.Text = readerSelectQuestion["DESCRIPTION"].ToString();
hlnkQuestionBy.Text = clsCommons.SayUserName(readerSelectQuestion["FK_OWNER_ID"].ToString());
hlnkQuestionBy.NavigateUrl = "AddMember.aspx?id=" + readerSelectQuestion["FK_OWNER_ID"].ToString();
lblAskedOn.Text = readerSelectQuestion["CREATED_ON"].ToString();
if (this.Session["UserId"].ToString() != "1")
{
btnUpdate.Visible = false;
txtEditorAnswer.Visible = false;
divQaDescription.Visible = true;
divQaDescription.InnerHtml = Server.HtmlDecode(readerSelectQuestion["ANSWER"].ToString());
}
else
{
txtEditorAnswer.Text = readerSelectQuestion["ANSWER"].ToString();
}
}
else
{
lblError.Text = "ERROR WHILE READING QA DATA!";
}
}
catch (Exception ex)
{
ExceptionLogger.LogException(ex);
lblError.Text = ex.Message;
}
finally
{
if (connectionSelectQuestion != null)
{
connectionSelectQuestion.Close();
}
}
}
What changes I need to make to get the plain text in the datagrid.
Thanks for ur help..
here is some sql code that can strip the tags for you.
declare #string varchar(max), --string to remove html from
#a varchar(max), --holds left part of string after removal
#b varchar(max) --holds right part of string after removal
set #string='<htlml><head><title></title></head><body>This is the body. <p>This is a paragraph.</p></body></html>'
declare #i bit, --determines if there are any more tags in the string
#start int, --position of the first < character
#end int --position of the first > character
set #i='false' --set default value
--set the positions of the first tag
select #start=CHARINDEX('<',#string),
#end=charindex('>',#string)
--only do the loop if there is a tag
if (#start>0 and #end>0) set #i='true'
while (#i='true')
begin
set #a='' --reset
set #b='' --reset
set #a=LEFT(#string,#start-1)
set #b=RIGHT(#string,len(#string)-#end)
--select #a, #b
set #string=#a+#b
select #start=CHARINDEX('<',#string),
#end=charindex('>',#string)
if (#start>0 and #end>0) set #i='true' else set #i='false'
end
select #string
keep in mind, however, that this code does not take into consideration if the text contains a < or >.

Resources