Question

I'm trying to use NPoco's Delete() method to delete a row from the database. However it just throws a NullReferenceException.

I have found a workaround, but I'm wondering if anyone knows why the built in delete function to delete by ID doesn't seem to work for me. This happens on multiple tables. All my tables have a standard integer primary key called ID, which has been flagged in the model using the [PrimaryKey("ID")] decorator.

Object reference not set to an instance of an object.

Delete<PurchaseItem>(id); // throws null reference exception.
Delete<PurchaseItem>("where id = @0", id);  // works.

The id being passed is valid an the item is in the database. The code does NOT get as far as executing any SQL.

Stack Trace:

[NullReferenceException: Object reference not set to an instance of an object.]
   NPoco.PocoDataFactory.ForObject(Object o, String primaryKeyName) in d:\Adam\projects\NPoco\src\NPoco\PocoDataFactory.cs:41
   NPoco.Database.Delete(String tableName, String primaryKeyName, Object poco, Object primaryKeyValue) in d:\Adam\projects\NPoco\src\NPoco\Database.cs:1587
   NPoco.Database.Delete(Object pocoOrPrimaryKey) in d:\Adam\projects\NPoco\src\NPoco\Database.cs:1598
   Harmsworth.DAL.HarmsworthDB.DeletePurchaseItemFromBasketByID(Int32 id) in c:\inetpub\wwwroot\harmsworth\Website\classes\HarmsworthDAL.cs:224
   Harmsworth.ViewBasketPage.RemoveItem(Int32 id) in c:\inetpub\wwwroot\harmsworth\Website\view-basket.aspx.cs:187
   Harmsworth.ViewBasketPage.PurchaseItemsRepeater_ItemCommand(Object sender, RepeaterCommandEventArgs e) in c:\inetpub\wwwroot\harmsworth\Website\view-basket.aspx.cs:75
   System.Web.UI.WebControls.Repeater.OnItemCommand(RepeaterCommandEventArgs e) +111
   [more redundant trace info]
Was it helpful?

Solution

Following the source in the GitHub repository it looks like there is a bug in NPoco:

You haven't specified what type id is, but I'm going to assume that it's an int and you have the following code:

var id = 12345;
Delete<PurchaseItem>(id);

Which calls NPoco Delete<T>(object pocoOrPrimaryKey), the code for which is:

public int Delete<T>(object pocoOrPrimaryKey)
{
    if (pocoOrPrimaryKey.GetType() == typeof(T))
        return Delete(pocoOrPrimaryKey);
    var pd = PocoDataFactory.ForType(typeof(T));
    return Delete(pd.TableInfo.TableName, pd.TableInfo.PrimaryKey, null, pocoOrPrimaryKey); // This is the method your code calls
}

Which in turn calls NPoco Delete(string tableName, string primaryKeyName, object poco, object primaryKeyValue), the code for which is:

public virtual int Delete(string tableName, string primaryKeyName, object poco, object primaryKeyValue)
{
    if (!OnDeleting(new DeleteContext(poco, tableName, primaryKeyName, primaryKeyValue))) return 0;
    var pd = PocoDataFactory.ForObject(poco, primaryKeyName);
    ...
}

I've only included the first 2 lines as it's the PocoDataFactory.ForObject method which throws the exception according to your stack trace. The code for ForObject(object o, string primaryKeyName) is:

public PocoData ForObject(object o, string primaryKeyName)
{
    var t = o.GetType(); // This is where the exception comes from
    ...
}

Here's what is happening (assuming the id is 12345, the table is mapped as PurchaseItem and the primary key is mapped as Id):

Delete<PurchaseItem>(pocoOrPrimaryKey : 12345);
Delete(tableName: "PurchaseItem", primaryKeyName: "Id", poco: null, primaryKeyValue: 12345);
PocoDataFactory.ForObject(o: null, primaryKeyName: Id);

The reason that Delete<PurchaseItem>("where id = @0", id); works, is that it follows a different code path where the type used to resolve the PocoData comes from typeof(T) where T is PurchaseItem.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top