Laden...

Generics und Entitäten (Linq2Sql)

Erstellt von exaveal vor 13 Jahren Letzter Beitrag vor 13 Jahren 1.115 Views
E
exaveal Themenstarter:in
96 Beiträge seit 2010
vor 13 Jahren
Generics und Entitäten (Linq2Sql)

Hallo.

Ich weiß nicht genau wie ich es beschreiben soll, daher gleich mal ein kurzes Codebeispiel:


        public void getResourceInfos<K, L>()
        {
            TGVDatabase context = new TGVDatabase(DatabaseConnection.getConnectionString());

            // Linq Query bauen
            Table<K> table1 = context.GetTable<K>();
            Table<L> table2 = context.GetTable<L>();

            var query = from t1 in table1
                        from t2 in table2
                        where t1.id == t2.id
                        select new { t1.id };
        }

Die Funktion an sich macht jetzt nicht viel Sinn, aber ich hoffe ihr erkennt was ich vor habe.
Ich habe eine Linq2Sql abfrage in einer Funktion. Ich möchte aber nun beim Aufruf der Funktion festlegen, auf welche Tabellen sich die Funktion beziehen soll. Ich verwende diese Abfrage sehr oft in meinem Programm und muss derzeit jedesmal die Funktion noch einmal schreiben, nur mit veränderten Tabellennamen.

Ich bin noch recht frisch bei der Sache, denke aber, dass ich die Generics prinzipiel verstanden habe. Wie ich eine generische Methode allerdings mit diesen für mich noch nicht ganz durchsichtigen Entitäten von Linq2Sql zusammenbringe, ist mir noch nicht ganz klar.

Zumindestens motzt mein Compiler wild, sobald ich es so versuche.

Danke im Voraus für die Mühe!

6.862 Beiträge seit 2003
vor 13 Jahren

Hallo,

Zumindestens motzt mein Compiler wild, sobald ich es so versuche.

Bitte immer [Hinweis] Wie poste ich richtig? Punkt 5 beachten. Hellsehen kann hier keiner...

An sich siehts relativ gut aus, das Problem wird wahrscheinlich sein das du ja im Query fest auf das Property id zugreifst und das kann der Kompiler natürlich nicht hinbekommen wenn überhaupt nicht klar ist welche Tabelle du überhaupt ansprichst.

Baka wa shinanakya naoranai.

Mein XING Profil.

E
exaveal Themenstarter:in
96 Beiträge seit 2010
vor 13 Jahren

Hy!

Sorry, das hätte ich wirklich gleich mitposten können.
Ich habe hier mal einen etwas bearbeiteten Screenshot. Die Kästen werden angezeigt wenn ich mir der Maus über die rot-unterringelnden Passagen fahre.

F
240 Beiträge seit 2006
vor 13 Jahren

Du musst K, L auf Referenztypen restriktieren (also where K : class in der Methodendefinition, siehe Generische Typenbeschränkung). Damit du die id property benutzen kannst, muss K bzw L natürlich diese properties bieten, also müssen sie ein interface implementieren. Somit sähe die Beschränkung so aus:


public void Method<K, L>() where K : class, ISomething, where L : class, IAnything
{
}

E
exaveal Themenstarter:in
96 Beiträge seit 2010
vor 13 Jahren

Das heißt, die Entitätsklassen, die VisualStudio mir mit der .dbml Datei automatisch erstellt, müßten das Interface erben.

Das wäre zwar theoretisch möglich, aber sehr umständlich zu realisieren. Oder sehe ich da was falsch?

T
156 Beiträge seit 2010
vor 13 Jahren

Was meinst Du mit umständlich zu realisieren? Also in dem generierten Code würde ich auch nicht eingreifen wollen, aber Du kannst Dir für die Entities, die das Interface implementieren sollen/müssen, partielle Klassen erstellen.
Marko

E
exaveal Themenstarter:in
96 Beiträge seit 2010
vor 13 Jahren

Ha, das gibts ja auch noch!
Vielen Dank, aber daran habe ich schon wieder garnicht mehr gedacht!.

Hab es zum laufen gebracht.

Meine Lösung:


public void getResourceInfos<K, L>()
    where T : class, ISomething
    where K : class, IAnything
{
    TGVDatabase context = new TGVDatabase(DatabaseConnection.getConnectionString());

    // Linq Query bauen
    Table<K> table1 = context.GetTable<K>();
    Table<L> table2 = context.GetTable<L>();

    var query = from t1 in table1
                from t2 in table2
                where t1.id == t2.id
                select new { t1.id };
}

und dazu die .cs Datei zur .dbml:


    public interface ISomething
    {
        int id { get; set; }
    }

    public partial class resources_texts : ISomething{}
    public partial class resources_files : ISomething{}
    public partial class resources_references : ISomething{}


    public interface IAnything
    {
        int id { get; set; }
    }

    public partial class linked_data : IAnything {}
    public partial class linked_preparationdata : IAnything {}

1.552 Beiträge seit 2010
vor 13 Jahren

Hallo exaveal,

anmerkend möchte ich sagen dass dein 2. Interface irgenwie nichts bringt, denn es können ja alle 5 aufgezeigten Klassen von ISomething oder von IAnything erben, da sie ja von Grund auf dieselben Eigenschaften implementierung erzwingen.

Gruß
Michael

Mein Blog
Meine WPF-Druckbibliothek: auf Wordpress, myCSharp

E
exaveal Themenstarter:in
96 Beiträge seit 2010
vor 13 Jahren

Hallo xxMUROxx,

ja das ist richtig, ich habe es nur so umgeschrieben, damit es an mein zuerst gepostetes Beispiel passt.
Die Interfaces sind dadurch identisch, meine eigentliche Methode schaut so aus:


        public ListViewItem[] getPreparationdataInfos<T, K>(string typ)
            where T : class, Ilinked_data
            where K : class, Iresources
        {
            TGVDatabase context = new TGVDatabase(DatabaseConnection.getConnectionString());

            // Linq Query bauen
            Table<T> linked_data = context.GetTable<T>();
            Table<K> resources = context.GetTable<K>();
            Table<modules> modules = context.GetTable<modules>();
            var query = from linking in linked_data
                        from resource in resources
                        from module in modules
                        where linking.course_id == id_course && linking.resource_id == resource.id_resource && resource.id_module == module.id_module
                        select new { module.id_module, module.title, module.language };

            // Dimensioniere list auf die Anzahl der items in query
            ListViewItem[] list = new ListViewItem[query.Count()];

            // ListViewItem zusammenbauen
            int i = 0;
            foreach (var item in query)
                list[i++] = new ListViewItem(new string[] { Convert.ToString(item.id_module), item.title, item.language, typ }, -1);

            return list;
        }

und die Interfaces so:


    public interface Iresources
    // Interface fuer die Tabellen resources_texts, resources_files und resources_references um gemeinsame
    // Basistabelle resources zu repraesentieren, da relationales Datenbankmodell keine Vererbungskonstrukte kennt.
    {
        int id_module { get; set; }
        int id_resource { get; set; }
    }

    public partial class resources_texts : Iresources {}
    public partial class resources_files : Iresources {}
    public partial class resources_references : Iresources {}


    public interface Ilinked_data
    // Interface fuer die Tabellen linked_data und linked_preparationdata um identisches Tabellendesign zu repraesentieren.
    {
        int course_id { get; set; }
        int resource_id { get; set; }
    }

    public partial class linked_data : Ilinked_data {}
    public partial class linked_preparationdata : Ilinked_data {}

Aber danke für den Einwand, für spätere Interessenten an dem Thread eine wichtige Anmerkung 😃