Общая идея начинается с создания элемента управления, который будет работать с любым объектом базы данных. Доступ к базе данных осуществляется через LINQ to SQL, а объекты базы данных автоматически генерируются из существующей базы данных.Как сделать производный класс использовать свойство базового класса?
Чтобы заставить управление работать с любым из этих объектов, я использую базовый интерфейс, из которого все наследуемые объекты сгенерированы. Таким образом, управление фактически работает с этим интерфейсом.
Этот интерфейс сначала должен обеспечивать:
- способность, чтобы получить идентификатор (первичный ключ) объекта
- выражение, которое будет возвращать этот идентификатор, если компилируется и вызывается через экземпляр объект
Так это выглядит следующим образом:
public interface IEntity<TEntity, TEntityId>
where TEntity : IEntity<TEntity, TEntityId>
where TEntityId : IEquatable<TEntityId>
{
Expression<Func<TEntity, TEntityId>> GetIdExpression();
TEntityId EntityId { get; }
}
Тогда определение класса объекта базы данных была бы выглядеть следующим образом:
//let it be the auto-generated part:
public partial class Entity1
{
public Guid UId { get; set; }
}
//and the manual part:
public partial class Entity1 : IEntity<Entity1, Guid>
{
public Expression<Func<Entity1, Guid>> GetIdExpression()
{
return (Expression<Func<Entity1, Guid>>)(se => se.UId);
}
public Guid EntityId
{
get { return this.UId; }
}
}
И мы можем проверить:
var e1 = new Entity1();
e1.UId = Guid.NewGuid();
Console.WriteLine(e1.UId);
Console.WriteLine(e1.GetIdExpression().Compile()(e1));
Выход этих двух линий равны. Все нормально.
Следующая идея состояла в том, что львиная доля всех объектов базы данных имеет идентификатор int
с именем Id
. И было бы намного лучше избегать редактирования каждого из них, т. Е. Не писать один и тот же код, реализующий IEntity<TEntity, TEntityId>
.
Насколько мне необходимо указать реализацию этого интерфейса, мне нужен класс. Сейчас я закончил с
public class IntEntity<TEntity> : IEntity<TEntity, int>
where TEntity : IntEntity<TEntity>
{
public int Id { get; set; }
public Expression<Func<TEntity, int>> GetIdExpression()
{
return (Expression<Func<TEntity, int>>)(e => e.Id);
}
public int EntityId
{
get { return this.Id; }
}
}
Тогда класс объектов базы данных могли бы извлечь из него:
//let it be the auto-generated part:
public partial class Entity2
{
public int Id { get; set; }
}
//and the manual part:
public partial class Entity2 : IntEntity<Entity2>
{
}
Уже сейчас очевидно, что Id
в Entity2
ли скрыть Id
в IntEntity<TEntity>
. Это подтверждается также и тем же тест:
var re = new Entity2();
re.Id = 5;
Console.WriteLine(re.Id); //5
Console.WriteLine(re.GetIdExpression().Compile()(re)); //0
Так что это решение не так ... я также судимым сделать IntEntity<TEntity>
абстрактно, но, очевидно, не удались, так как в Entity2
Id
определяются в авто сгенерированных частей, и я не смог сделать это override
abstract
Id
базового класса.
Есть ли что-нибудь, что я могу сделать, чтобы все объекты базы данных с int Id
использовали Id
с базой IntEntity<TEntity>
класс. Или, возможно, наоборот ...
Основным моментом здесь является то, что выражение возвращаемый GetIdExpression
должен иметь вид e => e.Id
, как это expresion позже будет использоваться в LINQ для запросов SQL, так что LINQ должен иметь возможность переводить это правильный SQL-запрос.
так почему вы должны 'id' недвижимость в' Entity2' и '' IntEntity, а не только один из них? –
Grundy
как вариант для решения - добавьте 'Id' в' IntEntity 'ключевое слово' virtual' и 'Id' в' Entity2' 'override' –
Grundy
@Grundy' Id' в 'Entity2' автогенерируется LINQ to SQL , Я не могу изменить его объявление. – horgh