2013-11-22 3 views
0

Общая идея начинается с создания элемента управления, который будет работать с любым объектом базы данных. Доступ к базе данных осуществляется через LINQ to SQL, а объекты базы данных автоматически генерируются из существующей базы данных.Как сделать производный класс использовать свойство базового класса?

Чтобы заставить управление работать с любым из этих объектов, я использую базовый интерфейс, из которого все наследуемые объекты сгенерированы. Таким образом, управление фактически работает с этим интерфейсом.

Этот интерфейс сначала должен обеспечивать:

  1. способность, чтобы получить идентификатор (первичный ключ) объекта
  2. выражение, которое будет возвращать этот идентификатор, если компилируется и вызывается через экземпляр объект

Так это выглядит следующим образом:

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> абстрактно, но, очевидно, не удались, так как в Entity2Id определяются в авто сгенерированных частей, и я не смог сделать это overrideabstractId базового класса.

Есть ли что-нибудь, что я могу сделать, чтобы все объекты базы данных с int Id использовали Id с базой IntEntity<TEntity> класс. Или, возможно, наоборот ...

Основным моментом здесь является то, что выражение возвращаемый GetIdExpression должен иметь вид e => e.Id, как это expresion позже будет использоваться в LINQ для запросов SQL, так что LINQ должен иметь возможность переводить это правильный SQL-запрос.

+0

так почему вы должны 'id' недвижимость в' Entity2' и '' IntEntity , а не только один из них? – Grundy

+0

как вариант для решения - добавьте 'Id' в' IntEntity 'ключевое слово' virtual' и 'Id' в' Entity2' 'override' – Grundy

+0

@Grundy' Id' в 'Entity2' автогенерируется LINQ to SQL , Я не могу изменить его объявление. – horgh

ответ

0

Я не уверен, что это именно то, что вы хотите, но вы можете попробовать сделать так

public abstract class IntEntity<TEntity> : IEntity<TEntity, int> 
    where TEntity : IntEntity<TEntity> 
{ 
    public abstract Expression<Func<TEntity, int>> GetIdExpression(); 
    public abstract int EntityId 
    { 
     get; 
    } 
} 

public partial class Entity2 
{ 
    public int Id { get; set; } 
} 
//and the manual part: 
public partial class Entity2 : IntEntity<Entity2> 
{ 
    public override int EntityId 
    { 
     get { return this.Id; } 
    } 

    public override Expression<Func<Entity2, int>> GetIdExpression() 
    { 
     return (Expression<Func<TEntity, int>>)(e => e.Id); 
    } 
} 

фактически без overridevirtual вы не можете получить доступ к полю в Dérivé класса от метода в базовом классе
в образце выше фактически равен ваш первый образец

UPDATE

в качестве временного решения вы можете добавить метамфетамин спосо SETID, которые устанавливают идентификатор в Dérivé и базового класса, как этот

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> 
{ 
    public void SetId(int id) 
    { 
     Id = id; 
     base.Id = id; 
    } 
} 

var re = new Entity2(); 
re.SetId(5); 
Console.WriteLine(re.Id); //5 
Console.WriteLine(re.GetIdExpression().Compile()(re)); //5 
+0

Это совсем не так ... – horgh

+0

@horgh что вы имеете в виду? – Grundy

+0

Я имею в виду, что я говорю ... Это вообще не решает проблему – horgh

Смежные вопросы