Laden...

Probleme mit Interfaces für generisches Repository

Erstellt von MorphieX vor 5 Jahren Letzter Beitrag vor 5 Jahren 1.477 Views
M
MorphieX Themenstarter:in
184 Beiträge seit 2012
vor 5 Jahren
Probleme mit Interfaces für generisches Repository

Hallo zusammen,

ich stehe gerade ein wenig auf dem Schlauch...
Ich starte gerade ein neues MVC-Projekt und möchte den Datenzugriff möglichst mit Interfaces entkoppeln. Dazu möchte möchte ich gerne ein generisches Repository als Basisklasse verwenden und davon meine spezifischen Repositories ableiten.

Ich habe dazu mal ein Minimalbeispiel erstellt.

Folgende Interfaces habe ich eingeführt:


public interface IEntityBase
{
  int Id { get; set; }
}

public interface IRepositoryBase<T> where T : IEntityBase
{
  T FindById(int id);
}

public interface IArtikel : IEntityBase
{
  String Name { get; set; }
}

public interface IArtikelRepository : IRepositoryBase<IArtikel>
{
  void DoSomething();
}

Daraus habe ich dann folgende Implementierungen erstellt:


public class EntityBase : IEntityBase
{
  public int Id { get; set; }
}

public class RepositoryBase<T> : IRepositoryBase<T> where T : IEntityBase
{
  public T FindById(int id)
  {
    // Irgendein Code:
    return Activator.CreateInstance<T>();
  }
}

public class Artikel : EntityBase, IArtikel
{
  public String Name { get; set; }
}

public class ArtikelRepository : RepositoryBase<Artikel>, IArtikelRepository
{
  public void DoSomething()
  {
    Console.WriteLine("...");
  }
}

Bei dem ArtikelRepository möchte ich also das IArtikelRepository implementieren, wovon das RepositoryBase aber schon die Methode FindById implementiert.
Ich gebe bei FindById T zurück, was im ArtikelRepository vom Typen Artikel ist. Artikel besitzt das Interface IArtikel - genau das erwartet IArtikelRepository auch.

Ich bekomme bei diesem Konstrukt aber folgende Fehlermeldung:> Fehlermeldung:

"ArtikelRepository" implementiert den Schnittstellenmember "IRepositoryBase<IArtikel>.FindById(int)" nicht. "RepositoryBase<Artikel>.FindById(int)" hat nicht den entsprechenden Rückgabetyp "IArtikel" und kann "IRepositoryBase<IArtikel>.FindById(int)" daher nicht implementieren.

Mir ist schon klar, dass IArtikelRepository als Rückgabewert ein "IArtikel" erwartet, ich aber ein "Artikel" zurückgebe. Aber Artikel ist doch IArtikel?! Ich bin etwas verwirrt...

Kann mich jemand aufklären? 😃

16.807 Beiträge seit 2008
vor 5 Jahren
  1. Die Einschränkung für Generics auf Klassen fehlt.
    Du kannst hier natürlich nicht mit Interfaces arbeiten, da Du davon keine Instanz erstellen kannst (und auch der ORM nicht) - aber Du hier die konkrete Klasse benötigst.
public interface IRepositoryBase<T> where T : class, IEntityBase
{
  T FindById(int id);
}
  1. Für Entitäten einfach Klassen verwenden, keine Interfaces
    Interfaces macht kein Sinn hier.
public class ArtikelEntity : IEntityBase
{
  public String Name { get; set; }
}

public interface IArtikelRepository : IRepositoryBase<ArtikelEntity>
{
  void DoSomething();
}

public class ArtikelRepository : RepositoryBase<ArtikelEntity>
{
  public void DoSomething()
  {
  }
}

Kein Overengineering notwendig 😉

M
MorphieX Themenstarter:in
184 Beiträge seit 2012
vor 5 Jahren

Okay, Danke 😃
Dein 2. Hinweis hat mich zum Ziel gebracht.

Ich bin davon ausgegangen dass es durchaus Sinn ergibt, auch die Entities zu entkoppeln, da ich Service -und Datenzugriffsschicht eigentlich trennen wollte. So könnte eine Entität aus einer Datenbank durchaus mehr oder weniger Eigenschaften benötigen als z.B. Entitäten aus einer OPC-Schnittstelle.

Aber darüber mache ich mir dann Gedanken

16.807 Beiträge seit 2008
vor 5 Jahren

Trotzdem wäre das eine Schichtverletzung, weil Du dann die Interfaces durchreichen würdest, was Dich stark bindet.
Es wäre mehr als ungewöhnlich, dass Dein Artikel in allen Schichten gleich aussieht.

Verwende pro Schicht eigene Modelle (Entities > Models > ViewModels) und übertrage deren Werte mit Hilfe von Mappern.