0

I am using Dapper.net as an ORM. I have an abstraact class called BusinessObject, which is inherited from by other classes that represent the tables in my database, for example SubContractorJob.

I have a method on the BusinessObject class called "Persist", which saves a record to the database:

public abstract class BusinessObject<T>
{
    public bool Persist<T>(IDbConnection db, T entity)
        where T : BusinessObject<T>, IDBObject
    {
        if (entity.Id > 0)
        {
            db.Update(entity);
            return true;
        }
        else
        {
            db.Insert(entity);
            return false;
        }
    }

}

Currently, as you can see, the Persist method takes an object as input.

Which means when I inherit from the BusinessObject class, I have to call it like this from my child object:

IDbConnection db = DBConnection.GetConnection();

    SubContractorJob s = new SubContractorJob()
            {
                Id = 3,
                SubContractorId = 6,
                JobId = 8,
                StartDate = DateTime.Today,
                EndDate = DateTime.Today.AddDays(10),
                EstimatedCost = 20000,
                ActualCost = 18000,
                IsDeleted = true
            }; 

s.Persist<SubContractorJob>(db, s);

My question is: How can I make this work without having to pass 's' when I am already calling the method in the context of s (the child object)?

I do have an interface (IDBObject) set up, so the child object is always guaranteed to have the Id field present.

I tried this:

public bool Persist<T>(IDbConnection db)
            where T : BusinessObject<T>, IDBObject
        {
            if ((typeof(T) as IDBObject).Id > 0)
            {
                db.Update(this);
                return true;
            }
            else
            {
                db.Insert(this);
                return false;
            }
        }

But got this error:

System.NullReferenceException : Object reference not set to an instance of an object.

Thanks for your help!

dpberry178
  • 558
  • 6
  • 21
  • What happens if you move `where T : BusinessObject, IDBObject` to the `BusinessObject` class definition? – mjwills Dec 10 '17 at 12:50
  • @mjwills, I did that and ran the "if ((typeof(T) as IDBObject).Id > 0)" version of the method and it failed with the same error. Is that what you were thinking I should do? – dpberry178 Dec 10 '17 at 12:56
  • Use `if (this.Id > 0)` not `if ((typeof(T) as IDBObject).Id > 0)`. _The latter makes no sense since the latter is trying to cast the `Type` not the object itself._ I **suspect** you meant to do if `((this as IDBObject).Id > 0)`, but even that `as` is unnecessary if you move the constraint to the class as I suggested earlier. – mjwills Dec 10 '17 at 13:01
  • @mjwills, thanks for the clarification. The problem I am having is that the compiler doesn't recognize `this.Id` as a valid field. – dpberry178 Dec 10 '17 at 13:07
  • @mjwills, I just tried `if ((this as IDBObject).Id > 0)` and it does exactly what I want! There is no Id field on my BusinessObject class; only the child class implements the interface. However, I am happy to use the solution above; it does what I need. – dpberry178 Dec 10 '17 at 13:11
  • @mjwills, yeah, I don't want to implement the interface from BusinessObject; I want to directly access the Id field from the child object, so this is perfect. If you want to add an answer I will gladly accept it! – dpberry178 Dec 10 '17 at 13:18

1 Answers1

3
if ((typeof(T) as IDBObject).Id > 0)

should be changed to:

if ((this as IDBObject).Id > 0)

The primary issue with your original code is that you are trying to cast a Type (from typeof) to IDBObject, rather than an object.

mjwills
  • 23,389
  • 6
  • 40
  • 63