То, что вы хотите сделать, не будет работать с LINQ to SQL. Чтобы использовать наследование с LINQ to SQL, вы должны использовать атрибут [InheritanceMapping] в вашем базовом классе. Допустим, у вас есть базовый класс Vehicle и подкласс Motorcycle:
[InheritanceMapping(Type = typeof(Motorcycle), IsDefault = true, Code = 1)]
[Table]
public class Vehicle
{
[Column]
public string Make { get; set; }
[Column]
public string Model { get; set; }
[Column(IsDiscriminator = true, Name="VehicleTypeId")]
public VehicleType VehicleType { get; set; }
}
public class Motorcycle : Vehicle
{
// implementation here
}
Чтобы это наследование работало в LINQ to SQL, необходимо применить [InheritanceMapping]
к базовому классу и , также необходимо иметь столбец дискриминатора (например, VehicleType в примере выше ). Обратите внимание, что код в InheritanceMapping равен «1» - это означает, что если VehicleType из базы данных равен «1», то он создаст подкласс Motorcycle. Вы применяете один атрибут [InheritanceMapping]
к базовому классу для каждого подкласса , который вы поддерживаете.
С точки зрения пуриста, это нарушение ОО, поскольку базовый класс знает о своих подклассах. Эта странность обычно отталкивает людей от того, как LINQ to SQL реализует наследование. Но там у вас есть.
Обновление
Это работает:
public abstract class BaseEntity<T, K> : IBaseEntity<K> where T : class, IBaseEntity<K>
{
public abstract K Id { get; set; }
public static Table<T> Table
{
get { return context.GetTable<T>(); }
}
public static T SearchById(K id)
{
return Table.Single<T>(t => t.Id.Equals(id));
}
public static void DeleteById(K id)
{
Table.DeleteOnSubmit(SearchById(id));
context.SubmitChanges();
}
}
Обратите внимание, что у меня нет атрибута [Column]
в свойстве Id. Также обратите внимание, я сделал это абстрактным. Реализующий класс выглядит так:
[Table(Name = "dbo.Contacts")]
public class Contact : BaseEntity<Contact, int>
{
[Column]
public override int Id { get; set; }
[Column]
public string FirstName { get; set; }
[Column]
public string LastName { get; set; }
}
Обратите внимание, что свойство Id
в этом классе имеет атрибут [Column]
, и я переопределяю абстрактные свойства. Итак, я проверил, что работает.
Сказав это, есть несколько причин, по которым я подвергаю сомнению ваш текущий дизайн. Сначала у вас есть методы доступа к данным как часть вашей сущности, и многие люди (включая меня) считают это нарушением разделения интересов. Вы можете ввести здесь шаблон Repository и иметь репозиторий для каждой сущности - сделать этот репозиторий универсальным, основываясь на типе и ключе. Другая вещь, которая странна в вышеупомянутом подходе, состоит в том, что BaseEntity
имеет свойство Id, а подкласс (в моем примере класс Contact
) также имеет свойство Id (чтобы сделать LINQ To SQL счастливым). Пришлось сделать свойство Id в базовом классе абстрактным, а затем переопределить его в конструкторе. Это нарушает СУХОЙ, потому что мне придется делать это для каждой сущности. Но это еще одна вещь, которая является результатом обручей, через которые вы должны перепрыгнуть, чтобы осчастливить LINQ to SQL. Но это будет работать! :)