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 ответа
Проведя небольшое исследование, я пришел к выводу, что не существует простого способа решить эту проблему прямой передачи унаследованного объекта. Можно сопоставить иерархии наследования, но это не имеет ничего общего с тем, что вы притворяетесь. Вы просто хотите отправить base
class
и не волнует, если это на самом деле является производным 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();
}