views:

641

answers:

3

I'm trying to insert a new object into my database using LINQ to SQL but get a NullReferenceException when I call InsertOnSubmit() in the code snippet below. I'm passing in a derived class called FileUploadAudit, and all properties on the object are set.

public void Save(Audit audit)
{
    try
    {                
        using (ULNDataClassesDataContext dataContext = this.Connection.GetContext())
        {
            if (audit.AuditID > 0)
            {
                throw new RepositoryException(RepositoryExceptionCode.EntityAlreadyExists, string.Format("An audit entry with ID {0} already exists and cannot be updated.", audit.AuditID));
            }

            dataContext.Audits.InsertOnSubmit(audit);
            dataContext.SubmitChanges();
        }
    }
    catch (Exception ex)
    {
        if (ObjectFactory.GetInstance<IExceptionHandler>().HandleException(ex))
        {
            throw;
        }
    }           
}

Here's the stack trace:

at System.Data.Linq.Table`1.InsertOnSubmit(TEntity entity)
at XXXX.XXXX.Repository.AuditRepository.Save(Audit audit) 
C:\XXXX\AuditRepository.cs:line 25"

I've added to the Audit class like this:

public partial class Audit
{ 
    public Audit(string message, ULNComponent component) : this()
    {
        this.Message = message;
        this.DateTimeRecorded = DateTime.Now;
        this.SetComponent(component);
        this.ServerName = Environment.MachineName;
    }           
    public bool IsError { get; set; }     
    public void SetComponent(ULNComponent component)
    {
        this.Component = Enum.GetName(typeof(ULNComponent), component);
    }
}

And the derived FileUploadAudit looks like this:

public class FileUploadAudit : Audit
{ 
    public FileUploadAudit(string message, ULNComponent component, Guid fileGuid, string originalFilename, string physicalFilename, HttpPostedFileBase postedFile)
        : base(message, component)
    {
        this.FileGuid = fileGuid;
        this.OriginalFilename = originalFilename;
        this.PhysicalFileName = physicalFilename;
        this.PostedFile = postedFile;
        this.ValidationErrors = new List<string>();
    }
    public Guid FileGuid { get; set; }
    public string OriginalFilename { get; set; }
    public string PhysicalFileName { get; set; }
    public HttpPostedFileBase PostedFile { get; set; }
    public IList<string> ValidationErrors { get; set; }
}

Any ideas what the problem is? The closest question I could find to mine is here but my partial Audit class is calling the parameterless constructor in the generated code, and I still get the problem.

UPDATE:

This problem only occurs when I pass in the derived FileUploadAudit class, the Audit class works fine. The Audit class is generated as a linq to sql class and there are no Properties mapped to database fields in the derived class.

+1  A: 

After doing a little research, I came to the conclusion that there's no easy way to solve this problem of submitting the inherited object directly. It's possible to Map Inheritance Hierarchies but this has nothing to do with what you pretend. You just want to submit the base class and don't care if it's actually a derived class.

If you don't want to use a partial class to add additional properties or behavior to your table class, as suggested in the thread you mentioned, I would do a simple Clone method as a workaround:

    public partial class Audit
    {
        // ...
        public Audit Concrete()
        {
            if (this.GetType().Equals(typeof(Audit)))
                return this;
            else
            {
                Audit audit = new Audit();
                // clone properties
                return audit;
            }
        }
    }

//...
dataContext.Audits.InsertOnSubmit(audit.Concrete());
bruno conde
Thanks, this is pretty much the conclusion I'd come to.
Charlie
A: 

Try creating a base abstract class that has only properties ID and typeDiscriminator; after that create the concrete class that inherits from the base and eventually other classes that inherits from the last one. Don't include properties in derived classes that are already presents in base one.

Example: Assuming a base abstract class named BasePeoples that has properties ID and typeDiscriminator, we have a class of type Person that inherits from the base and two other classes of type Fisherman and Driver that inherits form Person.

So you'll be able to do something like this

using (DatabaseDataContext db = new DatabaseDataContext())
        {
            Person p = new Person();
            p.FirstName = "Dario";
            p.LastName = "Iacampo";

            Fisherman f = new Fisherman();
            f.FirstName = "San";
            f.LastName = "Pei";
            f.CollectedFishes = 10;
            f.FishingLicenceNumber = "abc";

            Driver d = new Driver();
            d.FirstName = "Michael";
            d.LastName = "Shumaker";
            d.CarMake = "Ferrari";
            d.DrivingLicenceNumber = "123abc";

            db.BasePeoples.InsertOnSubmit(f);
            db.BasePeoples.InsertOnSubmit(d);
            db.SubmitChanges();

        }
JackNova
A: 

If you just want to pre-configure things, an alternative to inheritance might be:

partial class MyLinqClass {
    string Text = "Default";

    public MyLinqClass AsOne() {
        Text = "One";
        ...
        return this;
    }
}

var x = new MyLinqClass().AsOne();
context.InsertOnSubmit(x); // x is type MyLinqClass
Seba Illingworth