NullReferenceException при вызове InsertOnSubmit в Linq для Sql

Я пытаюсь вставить новый объект в свою базу данных, используя LINQ to SQL, но получаю исключение NullReferenceException, когда я вызываю InsertOnSubmit() в фрагменте кода ниже. Я передаю производный класс с именем FileUploadAudit, и все свойства объекта установлены.

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;
        }
    }           
}

Вот трассировка стека:

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

Я добавил в класс Audit вот так:

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);
    }
}

И производный FileUploadAudit выглядит так:

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; }
}

Есть идеи, в чем проблема? Самый близкий вопрос, который я могу найти, - здесь, но мой частичный класс Audit вызывает конструктор без параметров в сгенерированном коде, и я все еще получаю проблему.

ОБНОВИТЬ:

Эта проблема возникает только тогда, когда я передаю производный класс FileUploadAudit, класс Audit работает нормально. Класс Audit генерируется как класс linq to sql, и в производном классе нет свойств, сопоставленных с полями базы данных.

3 ответа

Решение

Проведя небольшое исследование, я пришел к выводу, что не существует простого способа решить эту проблему прямой передачи унаследованного объекта. Можно сопоставить иерархии наследования, но это не имеет ничего общего с тем, что вы притворяетесь. Вы просто хотите отправить baseclass и не волнует, если это на самом деле является производным class,

Если вы не хотите использовать partial class чтобы добавить дополнительные свойства или поведение к вашему классу таблицы, как предложено в упомянутой вами теме, я бы сделал простой метод Clone в качестве обходного пути:

    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());

Если вы просто хотите предварительно настроить вещи, альтернативой наследованию может быть:

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

Попробуйте создать базовый абстрактный класс, который имеет только свойства ID и typeDiscriminator; после этого создайте конкретный класс, который наследует от базового, и, в конце концов, другие классы, которые наследуют от последнего. Не включайте свойства в производные классы, которые уже представлены в базовом классе.

Пример: Предполагается, что базовый абстрактный класс с именем BasePeoples имеет свойства ID и typeDiscriminator, у нас есть класс типа Person, который наследуется от базового, и два других класса типа Fisherman и Driver, которые наследуют форму Person.

Таким образом, вы сможете сделать что-то вроде этого

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();

        }
Другие вопросы по тегам