none
Repository Pattern: Wie ein IEnumerable in einem DataModel füllen wenn die Entity eine andere ist? RRS feed

  • Frage

  • Hallo liebe User,

    ich habe mal eine Frage an der ich mir schon zwei Tage den Kopf zerbreche. 

    Und zwar bin ich gerade dabei das Repository Pattern zu implementieren in meine Anwendung (WebApi).

    Mein Problem ist nun das ich diese Fehlermeldung bekomme:

    Code:
    1:
    
    Cannot implicitly convert type 'System.Collections.Generic.IEnumerable<JobBusiness.Models.Employee.Employee>' to 'System.Collections.Generic.IEnumerable<JobBusiness.Models.Employee.EmployeeJob>'.

    Das ist auch logisch, wieso zeige ich nun:

    Ich habe ein DataLayer der von IRepository die Methoden erbt. 
    Dieser sieht so aus:

    C#-Code:
    using Dapper;
    using Npgsql;
    using System.Collections.Generic;
    using JobBusiness.Repositories;
    using System;
    using System.Linq;
    using System.Reflection;
    using System.ComponentModel.DataAnnotations;

    namespace JobBusiness.RepositoriesPostgresql
    {
        public abstract class AbstractPostgresqlRepository<TEntity,TPrimaryKey> : IRepository<TEntity, TPrimaryKey> where TEntity : BaseEntity<TPrimaryKey>
        {
            private string _connectionString;

            public AbstractPostgresqlRepository(string connectionString)
            {
                _connectionString = connectionString;
            }

            /*public IEnumerable<TEntity> Get(String strTableName)
            {
                using (NpgsqlConnection connection = new NpgsqlConnection(_connectionString))
                {
                    connection.Open();
                    string query = string.Format("SELECT * FROM {0}", strTableName);
                    return connection.Query<TEntity>(query);
                }
            }*/


            public IEnumerable<TEntity> Get(String strTableName, String strColumns, int ID)
            {
                using (NpgsqlConnection connection = new NpgsqlConnection(_connectionString))
                {
                    connection.Open();
                    string query = string.Format("SELECT {0} FROM {1} WHERE Id = {2}", strColumns ,strTableName, ID);
                    return connection.Query<TEntity>(query);
                }
            }

            public IEnumerable<TEntity> Get(String sql)
            {
                using (NpgsqlConnection connection = new NpgsqlConnection(_connectionString))
                {
                    connection.Open();
                    return connection.Query<TEntity>(sql);
                }
            }

            public TEntity GetSingelEntity(String sql)
            {
                using (NpgsqlConnection connection = new NpgsqlConnection(_connectionString))
                {
                    connection.Open();
                    return connection.Query<TEntity>(sql).First();
                }
            }

            public TEntity Get(TPrimaryKey id)
            {
                using (NpgsqlConnection connection = new NpgsqlConnection(_connectionString))
                {
                    connection.Open();
                    string query = string.Format("SELECT * FROM {0} WHERE Id = @Id LIMIT 1", TableName);
                    return connection.Query<TEntity>(query, new { Id = id }).First();;
                }
            }

            public void Add(TEntity entity)
            {
                using (NpgsqlConnection connection = new NpgsqlConnection(_connectionString))
                {
                    connection.Open();

                    IEnumerable<KeyValuePair<stringstring>> RowsAndValues = ResolveProperties(entity);
                    IEnumerable<string> keys = RowsAndValues.Select(c => c.Key);
                    IEnumerable<string> values = RowsAndValues.Select(c => c.Value);
                    string query = string.Format("INSERT INTO {0} ({1}) VALUES ({2});", TableName, string.Join(",",keys), string.Join(",", values));
                    connection.Execute(query);
                }
            }

            public void Update(TEntity entity)
            {
                using (NpgsqlConnection connection = new NpgsqlConnection(_connectionString))
                {
                    connection.Open();

                    IEnumerable<KeyValuePair<stringstring>> RowsAndValues = ResolveProperties(entity);
                    IEnumerable<string> keys = RowsAndValues.Select(c => c.Key);
                    IEnumerable<string> values = RowsAndValues.Select(c => c.Value);
                    string query = string.Format("UPDATE {0} SET ({1}) = ({2}) WHERE Id = @Id;", TableName, string.Join(",", keys), string.Join(",", values));
                    connection.Execute(query, new { Id = entity.Id });
                }
            }

            public void Remove(TEntity entity)
            {
                using (NpgsqlConnection connection = new NpgsqlConnection(_connectionString))
                {
                    connection.Open();
                    string query = string.Format("DELETE FROM {0} WHERE Id = @Id", TableName);
                    connection.Execute(query, new { Id = entity.Id });
                }
            }

            private IEnumerable<KeyValuePair<stringstring>> ResolveProperties(TEntity entity)
            {
                List<KeyValuePair<stringstring>> result = new List<KeyValuePair<stringstring>>();

                PropertyInfo[] infos = entity.GetType().GetProperties();
                foreach (PropertyInfo info in infos)
                {
                    if(info.GetCustomAttribute<KeyAttribute>() == null)
                    {
                        result.Add(new KeyValuePair<stringstring>(info.Name, string.Format("'{0}'", info.GetValue(entity))));
                    }
                }

                return result;
            }

            //protected abstract string TableName { get; }
        }
    }

    Mein Repository zum Implementieren von Zusatzcode sieht wie folgt aus:

    C#-Code:
    using JobBusiness.Repositories;
    using JobBusiness.Models.Employee;
    using JobBusiness.RepositoriesPostgresql;

    namespace JobBusiness.Repositories
    {
        public class EmployeeRepository : AbstractPostgresqlRepository<Employee, int>, IEmployeeRepository
        {
            public EmployeeRepository(string connectionString) : base(connectionString)
            {

            }

            public Employee getEmployee (int ID)
            {
                Employee SingelEmployee;
                SingelEmployee = base.GetSingelEntity("SELECT id, description From Employee where id =" + ID.ToString());
                SingelEmployee.IEnumEmployeeJob = base.Get("SELECT ID from EmployeeJob WHERE IDEmployee = " + ID.ToString());
                return SingelEmployee;
            }

        }
    }

    Dazu habe ich noch zwei Datamodels:
    Employee:

    C#-Code:
    using System.Collections.Generic;
    using JobBusiness.Repositories;

    namespace JobBusiness.Models.Employee
    {
        public class Employee : BaseEntity<int>
        {
            public string display_name { getset; }
            public string description { getset; }
            public IEnumerable<EmployeeJob> IEnumEmployeeJob;
        }
    }

    Was einen einzelnen Arbeiter darstellt. Allerdings hat jeder Arbeiter eine Liste mit Jobs für die er qualifiziert ist. Also hat mein Model für den Employee noch die Ienumerable<EmployeeJob>:

    C#-Code:
    using JobBusiness.Repositories;

    namespace JobBusiness.Models.Employee
    {
        public class EmployeeJob : BaseEntity<int>
        {
            public string IDEmployeeJob { getset; }
            public string name { getset; }
            public string description { getset; }
        }
    }

    Das Problem ist nun das in meinem Repository für den Employee möchte ich eine Methode machen um einen Arbeiter und seine Jobs zu erhalten als Rückgabewert:

    C#-Code:
    public Employee getEmployee (int ID)
            {
                Employee SingelEmployee;
                SingelEmployee = base.GetSingelEntity("SELECT id, description From Employee where id =" + ID.ToString());
                SingelEmployee.IEnumEmployeeJob = base.Get("SELECT ID from EmployeeJob WHERE IDEmployee = " + ID.ToString());
                return SingelEmployee;
            }

    Das funktioniert bis zu dieser Zeile:

    C#-Code:
    SingelEmployee.IEnumEmployeeJob = base.Get("SELECT ID from EmployeeJob WHERE IDEmployee = " + ID.ToString());

    Da das Repository vom DataAccessLayer erbt und bei der Instanziierung der Typ auf Employee gesetzt wird:

    C#-Code:
    public class EmployeeRepository : AbstractPostgresqlRepository<Employee, int>, IEmployeeRepository

    Somit kann ich in meiner Funktion diese Zeile nicht ausführen:

    C#-Code:
    SingelEmployee.IEnumEmployeeJob = base.Get("SELECT ID from EmployeeJob WHERE IDEmployee = " + ID.ToString());

    Da das IEnumerable von einem anderen Typen ist, und zwar von EmployeeJob und nicht Employee und mir die BaseFunktion nur ein Employee in dem Fall zurück geben kann.

    Aber ich habe keine Lösung wie ich das nun Ändern bzw Anpassen kann.
    das repository Pattern finde ich gut aber ich bin damit nicht so erfahren.

    Hat jemand vielleicht einen Vorschlag wie man so einen Fall handel kann? 
    Ich muss ja irgendwie die Liste bzw. das IEnumerable gefüllt bekommen. Ich hatte überlegt noch extra weitere Klassen für diesen Typen zu erstellen aber dann bin ich schnell mal bei 30+Klassen irgendwann.

    Für die Injection verwende ich folgende Zeile:

    C#-Code:
    services.AddSingleton<IEmployeeRepository, EmployeeRepository>(parameter => new EmployeeRepository(connection));

    Freu mich über jede Hilfe :)
    Sonntag, 25. November 2018 22:08

Alle Antworten

  • Hi Olli,
    mit AbstractPostgresqlRepository<Employee, int> legst Du den Rückgabetyp fest. Damit liefert Dein Get eine IEnumerable of Employee und die Zuweisung an IEnumerable<EmployeeJob> IEnumEmployeeJob bringt Fehler, da EmployeeJob nicht die Basisklasse von Employee ist. Es ist also ein Designfehler. Eine Lösung wäre eine separate Klasse für EmployeeJob.

    --
    Viele Grüsse
    Peter Fleischer (ehem. MVP für Developer Technologies)
    Meine Homepage mit Tipps und Tricks

    Montag, 26. November 2018 07:39