Edit and Delete not working with SfGrid and CustomAdaptor (Syncfusion.Blazor 18.1.0.42)

Hello,

I'm using an SfGrid with a custom adaptor:

@inject ArticleAdapter ArticleAdapter

...

<SfGrid TValue="Article" ID="Grid" AllowSorting="true"  AllowFiltering="true"  AllowPaging="true" Toolbar="@(new List<string>() { "Add", "Edit", "Delete", "Cancel", "Update" })" Height="315">
            <SfDataManager AdaptorInstance="@typeof(ArticleAdapter)" Adaptor="Adaptors.CustomAdaptor"></SfDataManager>
            <GridEditSettings AllowAdding="true" AllowEditing="true" AllowDeleting="true" AllowNextRowEdit="true"  Mode="@EditMode.Normal"></GridEditSettings>
</SfGrid>

Adding rows works fine and InsertAsync gets called in my custom adaptor (ArticleAdapter), so the adapter initialization and setup seems fine. But when I click Delete or Update (after an edit) nothing happens. Any breakpoints are not triggered in my customa adaptor, so the calls are not even getting there, and no logs/exceptions are seen.
So, shortly, UpdateAsync and RemoveAsync are never being called from the SfGrid. And also same result when using synchronous methods.

My ArticleAdapter:

namespace XXX
{
    public abstract class IAHObject
    {
        [Key]
        [BsonId]
        public ObjectId ID { get; set; }

    }

    [BsonIgnoreExtraElements]
    public class Article : IAHObject
    {
        public string Title { get; set; }
    }


    public class ArticleAdapter : AHDataAdapter<Article>
    {
        public ArticleAdapter(ApplicationDbContext db) : base(db.ArticleCollection)
        {
        }
    }

    // Implementing custom adaptor by extending the DataAdaptor class
    public class AHDataAdapter<T> : DataAdaptor where T: IAHObject
    {
        private readonly IMongoCollection<T> collection;

        public AHDataAdapter(IMongoCollection<T> collection)
        {
            this.collection = collection;
        }

        public override object Read(DataManagerRequest dm, string key = null)
        {
            IEnumerable<T> DataSource = collection.AsQueryable().AsEnumerable();
            if (dm.Search != null && dm.Search.Count > 0)
            {
                // Searching
                DataSource = DataOperations.PerformSearching(DataSource, dm.Search);
            }
            if (dm.Sorted != null && dm.Sorted.Count > 0)
            {
                // Sorting
                DataSource = DataOperations.PerformSorting(DataSource, dm.Sorted);
            }
            if (dm.Where != null && dm.Where.Count > 0)
            {
                // Filtering
                DataSource = DataOperations.PerformFiltering(DataSource, dm.Where, dm.Where[0].Operator);
            }
            int count = DataSource.Cast<T>().Count();
            if (dm.Skip != 0)
            {
                //Paging
                DataSource = DataOperations.PerformSkip(DataSource, dm.Skip);
            }
            if (dm.Take != 0)
            {
                DataSource = DataOperations.PerformTake(DataSource, dm.Take);
            }
            return dm.RequiresCounts ? new DataResult() { Result = DataSource, Count = count } : (object)DataSource;
        }

        public override async Task<object> InsertAsync(DataManager dataManager, object value, string key)
        {
            T item = (T)value;
            await collection.InsertOneAsync((T)item);
            return item;
        }

        public override async Task<object> RemoveAsync(DataManager dataManager, object value, string keyField, string key)
        {
            await collection.DeleteOneAsync<T>(or => or.ID == ObjectId.Parse(value.ToString()));
            return value;
        }

        public override async Task<object> UpdateAsync(DataManager dm, object value, string keyField, string key)
        {
            T item = (T)value;
            await collection.ReplaceOneAsync<T>(or => or.ID == item.ID, item);
            return value;
        }

        // Performs BatchUpdate operation
        public override object BatchUpdate(DataManager dm, object Changed, object Added, object Deleted, string KeyField, string Key, int? dropIndex)
        {
            IEnumerable<T> Orders = collection.AsQueryable().AsEnumerable();
            if (Changed != null)
            {
                foreach (var item in (IEnumerable<T>)Changed)
                {
                    collection.ReplaceOne<T>(or => or.ID == item.ID, item);
                }

            }
            if (Added != null)
            {
                foreach (var item in (IEnumerable<T>)Added)
                {
                    collection.InsertOne(item);
                    //Orders.Add(rec);
                }

            }
            if (Deleted != null)
            {
                foreach (var item in (IEnumerable<T>)Deleted)
                {
                    collection.DeleteOne<T>(or => or.ID == item.ID);
                    //Orders.RemoveAt(0);
                }

            }
            return Orders;
        }
    }
}




11 Replies

SG Sture Gustafsson April 6, 2020 04:07 PM UTC

Small update,

no exceptions are seen in the browser when trying to Edit, nothing just happens.

But the below exceptions happen with trying to Select or Delete a row.


This happens when selecting a row:

blazor.server.js:8 Uncaught (in promise) Error: There was an exception invoking 'Trigger'. For more details turn on detailed exceptions in 'CircuitOptions.DetailedErrors'
    at Object.endInvokeDotNetFromJS (blazor.server.js:8)
    at e.<anonymous> (blazor.server.js:8)
    at blazor.server.js:1
    at Array.forEach (<anonymous>)
    at e.invokeClientMethod (blazor.server.js:1)
    at e.processIncomingData (blazor.server.js:1)
    at e.connection.onreceive (blazor.server.js:1)
    at WebSocket.i.onmessage (blazor.server.js:1)
endInvokeDotNetFromJS @ blazor.server.js:8
(anonymous) @ blazor.server.js:8
(anonymous) @ blazor.server.js:1
e.invokeClientMethod @ blazor.server.js:1
e.processIncomingData @ blazor.server.js:1
connection.onreceive @ blazor.server.js:1
i.onmessage @ blazor.server.js:1



When trying to Delete:

articlelist2:1 Uncaught (in promise) {dm: e, data: "5e8b4fe26042fa5b2485514c", keyField: "ID", tableName: undefined, query: e, …}
Promise.then (async)
e.getData @ grids-ec5227.min.js:1
e.blazorCallback @ syncfusion-blazor.min.js:1
e.notify @ syncfusion-blazor.min.js:1
r.notify @ syncfusion-blazor.min.js:1
(anonymous) @ grids-ec5227.min.js:1
e.blazorCallback @ syncfusion-blazor.min.js:1
e.blazorCallback @ syncfusion-blazor.min.js:1
e.blazorCallback @ syncfusion-blazor.min.js:1
e.notify @ syncfusion-blazor.min.js:1
e.trigger @ syncfusion-blazor.min.js:1
t.refresh @ grids-ec5227.min.js:1
e.blazorCallback @ syncfusion-blazor.min.js:1
e.blazorCallback @ syncfusion-blazor.min.js:1
e.blazorCallback @ syncfusion-blazor.min.js:1
e.notify @ syncfusion-blazor.min.js:1
r.notify @ syncfusion-blazor.min.js:1
e.deleteRecord @ grids-ec5227.min.js:1
t.deleteRecord @ grids-ec5227.min.js:1
e.deleteRecord @ grids-ec5227.min.js:1
r.deleteRecord @ grids-ec5227.min.js:1
(anonymous) @ grids-ec5227.min.js:1
e.notify @ syncfusion-blazor.min.js:1
e.trigger @ syncfusion-blazor.min.js:1
e.toolbarClickHandler @ grids-ec5227.min.js:1
e.blazorCallback @ syncfusion-blazor.min.js:1
e.notify @ syncfusion-blazor.min.js:1
e.trigger @ syncfusion-blazor.min.js:1
t.clickHandler @ navigations-ec5227.min.js:1



SG Sture Gustafsson April 6, 2020 07:14 PM UTC

I'll add my same reply here as in another thread, in case someone else runs into the same issue.

If the Article class, which is used in the row, contains a property of type MongoDB.Bson.ObjectId then SfGrid Edit + Delete + RowSelected do not work.
Changing only the type to int causes everything to work fine. But, I would need ObjectId to work for my project...

Does not work:
        [Key]
        public ObjectId ID { get; set; }  //type is MongoDB.Bson.ObjectId


Does work:
        [Key]
        public int ID { get; set; }

-sture



RN Rahul Narayanasamy Syncfusion Team April 7, 2020 12:41 PM UTC

Hi Sture,  

Greetings from Syncfusion. 

Query: “Edit and Delete not working with SfGrid and CustomAdaptor (Syncfusion.Blazor 18.1.0.42)” 

We have validated your query and checked the reported problem by creating a sample based on your requirement. It works fine at our end. Find the below code snippets and sample for your reference. 

. . . 
 
    <SfGrid @ref="DefaultGrid" TValue="Order" AllowFiltering="true" Toolbar="@(new List<string> {"Add", "Edit", "Delete", "Cancel", "Update","Search" })" AllowPaging="true"> 
        <SfDataManager AdaptorInstance="@typeof(CustomAdaptor)" Adaptor="Adaptors.CustomAdaptor"></SfDataManager> 
        <GridEditSettings AllowEditing="true" AllowDeleting="true" AllowAdding="true"></GridEditSettings> 
        . . . 
    </SfGrid> 
@code{ 
    SfGrid<Order> DefaultGrid { get; set; } 
    . . . 
    // Implementing custom adaptor by extending the DataAdaptor class 
    public class CustomAdaptor : DataAdaptor 
    { 
        // Performs data Read operation 
        public override object Read(DataManagerRequest dm, string key = null) 
        { 
            . . . 
            return dm.RequiresCounts ? new DataResult() { Result = DataSource, Count = count } : (object)DataSource; 
        } 
 
        // Performs Insert operation 
        public override object Insert(DataManager dm, object value, string key) 
        { 
            Orders.Insert(0, value as Order); 
            return value; 
        } 
 
        // Performs Remove operation 
        public override object Remove(DataManager dm, object value, string keyField, string key) 
        { 
            Orders.Remove(Orders.Where(or => or.OrderID == int.Parse(value.ToString())).FirstOrDefault()); 
            return value; 
        } 
 
        // Performs Update operation 
        public override object Update(DataManager dm, object value, string keyField, string key) 
        { 
            var data = Orders.Where(or => or.OrderID == (value as Order).OrderID).FirstOrDefault(); 
            if (data != null) 
            { 
                data.OrderID = (value as Order).OrderID; 
                data.CustomerID = (value as Order).CustomerID; 
                data.Freight = (value as Order).Freight; 
            } 
            return value; 
        } 
    } 
} 

For your convenience we have prepared a sample using ObjectId property using our latest version. Please find the sample from below  


Please get back to us if you need further assistance. 

Regards, 
Rahul 



SG Sture Gustafsson April 7, 2020 07:41 PM UTC

Thanks, the reason for my problem was the same as I had in another thread.
My ObjectID was of type MongoDB.Bson.ObjectId, and that caused all the problems, changing it to int or string was enough to get everything working.

EDITED: Ignore the part below, I was able to figure it out, it was with Grid2Reference.Refresh(); 

But I now phase another issue when this is working. I modify something inside the RowSelected handler which would affect what should be shown in another grid. That other grid gets a parameter in a CustomAdaptorComponent (inherited from DataAdaptor). I can see in the debugger that everything get setup correctly, but how can I programmatically force that other grid to refresh (i.e. call the Read function of the CustomAdaptorComponent)?

-sture



RN Rahul Narayanasamy Syncfusion Team April 8, 2020 12:02 PM UTC

Hi Sture, 

Thanks for the update. 

Yes, you can refresh the Grid by using GridReference.Refresh() method of the Grid as you mentioned. 

We are happy to hear that you have achieved your requirement. Please get back to us if you need further assistance. 

Regards, 
Rahul 




ZB Zac Boyles September 8, 2020 10:40 PM UTC

I'm also running into the issue where only partial overridden methods on my custom DataAdaptor are being triggered. Read/ReadAsync and Insert/InsertAsync all work fine and I can use the either sync/async method successfully.

The breakpoints on Update/UpdateAsync/Remove overridden methods are never triggered. I'm using EF Core and my dbcontext object is injected in the constructor. As mentioned, this works for Read/Insert operations. I've removed all but one or two columns, I've removed the default query object, I've tried confirmation dialog options. Disabled sorting and filtering and removed any extra options but no matter what my update/remove breakpoints are not triggered in the DataAdapter.

Is there a common mistake I'm making? Sture seems to mention data annotations on his data class might have caused some issue however my Entity class was only using [MaxLength(n)], [Required], and a few with [NotMapped]. I've removed them all but still run into the issue. It's like the grid is not firing these events.

Also, I'm not having an issue where the grid isn't refreshing. The underlying SQL db is not updating/deleting, just reading and inserting.


RN Rahul Narayanasamy Syncfusion Team September 9, 2020 02:19 PM UTC

Hi Zac, 

Greetings from Syncfusion. 

Query: Updating/deleting not working while using custom adaptor 

We have validated your query and checked the reported problem at our end. We could not reproduce the reported problem. The update and delete operations are working without any issues. Find the below sample for your reference. 


If you are still facing the problem, could you please share the below details. It will be helpful to validate and provide a better solution. 

  • Reproduce the problem in the provided sample and revert back to us.
  • Share a simple reproduceable sample if possible.

Regards, 
Rahul 



TC Thomas Crosman May 2, 2022 02:25 PM UTC

Also having this problem.  Giving up on using the CustomDataAdaptors at this point.



RS Renjith Singh Rajendran Syncfusion Team May 3, 2022 10:04 AM UTC

Hi Thomas,


Please refer the sample attached from our previous update and check this from your side. If you are still facing difficulties, kindly share with us the details requested from our previous update to further proceed on this scenario and provide you a solution as early as possible.


Regards,

Renjith R



RG Riley Grant replied to Thomas Crosman October 4, 2022 06:52 PM UTC

It's been a while since you posted this. Perhaps you figured it out already but, in order to make this work, you need to make sure to include the Primary Key in the grid as a hidden column and denote it as IsPrimaryKey.


<GridColumn Field="@nameof(YOURCLASS.ID)" IsPrimaryKey="true" Visible="false" />




SP Sarveswaran Palani Syncfusion Team October 5, 2022 03:59 PM UTC

Hi Riley,

Thanks for taking time to update us.

We'll take your suggestion and implement further in related queries.

Regards,

Sarveswaran PK


Loader.
Up arrow icon