Frage

Ich habe einige Arten, die eine gemeinsame Art erweitern, und diese sind meine Modelle.

Ich habe dann DAO-Typen für jeden Modelltyp für CRUD-Operationen.

ich jetzt eine Notwendigkeit für eine Funktion haben, die mir erlauben, eine ID jedes Modell Typ gegeben zu finden, so dass ich einen neuen Typ für einige Zusatz-Funktionen erstellt.

Das Problem ist, dass ich weiß nicht, wie diese Art bestellen. Zur Zeit habe ich Modelle vor dao, aber ich brauche irgendwie DAOMisc vor CityDAO und CityDAO vor DAOMisc, was nicht möglich ist.

Der einfache Ansatz, um diese Funktion in jedem DAO zu setzen wäre, die sich auf nur die Typen, die, bevor sie kommen, so kommt State vor City als State hat eine Fremdschlüsselbeziehung mit City, so dass die Zusatz-Funktion sehr wäre kurz. Aber dies scheint mir genauso falsch, so dass ich nicht sicher bin, wie man am besten diesen Ansatz.

Hier ist meine verschieden Typ, wo BaseType ist eine häufige Art für alle meine Modelle.

type DAOMisc =
    member internal self.FindIdByType item = 
        match(item:BaseType) with
        | :? StateType as i -> 
            let a = (StateDAO()).Retrieve i
            a.Head.Id
        | :? CityType as i -> 
            let a = (CityDAO()).Retrieve i
            a.Head.Id
        | _ -> -1

Hier ist ein dao Typ. CommonDAO tatsächlich hat den Code für die CRUD-Operationen, aber das ist hier nicht wichtig.

type CityDAO() =
    inherit CommonDAO<CityType>("city", ["name"; "state_id"], 
        (fun(reader) ->
            [
                while reader.Read() do
                    let s = new CityType()
                    s.Id <- reader.GetInt32 0
                    s.Name <- reader.GetString 1
                    s.StateName <- reader.GetString 3
            ]), list.Empty
    )

Das ist mein Modelltyp:

type CityType() =
    inherit BaseType()
    let mutable name = ""
    let mutable stateName = ""
    member this.Name with get() = name and set restnameval=name <- restnameval
    member this.StateName with get() = stateName and set stateidval=stateName <- stateidval
    override this.ToSqlValuesList = [this.Name;]
    override this.ToFKValuesList = [StateType(Name=this.StateName);]

Der Zweck dieser FindIdByType Funktion ist, dass ich die ID für eine Fremdschlüsselbeziehung finden will, so dass ich den Wert in meinem Modell setzt und habe dann die CRUD-Funktionen machen die Operationen mit all den richtigen Informationen. Also, City die ID für den Staatsnamen benötigt, so dass ich den Staat Namen bekommen würde, steckte es in die state Typ, dann diese Funktion aufrufen, die id für diesen Zustand zu erhalten, so dass meine Stadt Einsatz wird auch die ID für den ausländischen umfassen Taste.

Dies scheint der beste Ansatz, in sehr allgemeine Weise zu Griffeinsätzen zu sein, die das aktuelle Problem ist, ich zu lösen versuchen.

UPDATE:

Ich muss die Forschung und sehen, ob ich irgendwie kann spritzen die FindIdByType Methode in die CommonDAO nach allen anderen DAOs definiert wurden, fast, als ob es sich um eine Schließung ist. Wenn diese Java würde ich AOP verwenden, um die Funktionalität zu erhalten ich suche, nicht sicher, wie diese # in F zu tun.

Schluss Update:

Nach dem Denken über meinen Ansatz wurde mir klar, es war tödlich fehlerhaft, so dass ich mit einem anderen Ansatz kam.

Dies ist, wie ich einen Einsatz tun, und ich beschloß, diese Idee in jede Einheit Klasse zu setzen, die wahrscheinlich eine bessere Idee ist.

member self.Insert(user:CityType) =
    let fk1 = [(StateDAO().Retrieve ((user.ToFKValuesList.Head :?> StateType), list.Empty)).Head.Id]
    self.Insert (user, fk1)

Ich habe die fklist verwendet noch nicht begonnen, aber es ist int list und ich weiß, welchen Spalt Name mit jedem geht, so dass ich zum Beispiel nur tun müssen, um inner join für wählt.

Dies ist der Basistyp Einsatz, der verallgemeinert:

member self.Insert(user:'a, fklist) =
    self.ExecNonQuery (self.BuildUserInsertQuery user)

Es wäre schön, wenn F # co / Kontravarianz tun konnte, so dass ich um diese Einschränkung zu arbeiten hatte.

War es hilfreich?

Lösung

Dieses Beispiel ist sehr weit von dem, was ich in der funktionalen Programmierung gewöhnt bin. Aber für das Problem von sich gegenseitig rekursive Typen Bestellung, gibt es eine Standardlösung: Parameter Nutzungsart und machen Zwei-Ebenen-Typen. Ich werde ein einfaches Beispiel in OCaml, einer verwandten Sprache geben. Ich weiß nicht, wie das einfache Beispiel in die beängstigenden Art Funktionen übersetzen Sie verwenden.

Hier ist, was nicht funktioniert:

type misc = State of string
          | City  of city

type city = { zipcode : int; location : misc }

Hier ist, wie Sie es mit Zwei-Ebenen-Typen zu beheben:

type 'm city' = { zipcode : int; location : 'm }

type misc = State of string
          | City of misc city'
type city = misc city'

Dieses Beispiel ist OCaml, aber vielleicht können Sie zu F # verallgemeinern. Hoffe das hilft.

Andere Tipps

In F # ist es möglich, zu definieren für beide Seiten rekursive Typen , das heißt, können Sie die beiden Typen definieren, die Notwendigkeit, sich zusammen zu verweisen und sie werden sich gegenseitig sehen. Die Syntax für das Schreiben ist dies:

type CityDAO() = 
  inherit CommonDAO<CityType>(...)
  // we can use DAOMisc here

and DAOMisc = 
  member internal self.FindIdByType item =  
    // we can use CityDAO here

Die Einschränkung dieser Syntax ist, dass sowohl die Typen müssen in einer einzigen Datei deklariert werden, so dass Sie nicht die typische C # Organisation 1 Typ pro 1 Datei verwenden können.

Wie Norman weist darauf hin, dies ist kein typisches funktionales Design, so dass, wenn Sie die gesamte Datenzugriffsschicht in einem funktional gestaltet, werden Sie wahrscheinlich dieses Problem vermeiden konnten. Ich würde jedoch sagen, dass es nichts falsch mit Kombination von funktionalen und objektorientierten Stil in F #, also für beide Seiten rekursive Typen verwendet, kann die einzige Option sein.

Sie können sich wahrscheinlich den Code schreiben mehr schön, wenn Sie erste Schnittstellen für die beiden Typen definieren - diese können oder sich nicht gegenseitig rekursiv sein müssen, kann (je nachdem, ob man in der öffentlichen Schnittstelle des anderen verwendet wird):

type ICityDAO = 
  abstract Foo : // ...

type IDAOMisc = 
  abstract Foo : // ...

Dies hat folgende Vorteile:

  • definieren alle gegenseitig rekursive Schnittstellen in einer einzigen Datei machen nicht den Code weniger lesbar
  • Sie können später auf die Schnittstellen beziehen, so dass keine anderen Typen müssen sich gegenseitig rekursive
  • sein
  • Als Nebeneffekt, werden Sie mehr erweiterbaren Code haben (dank Schnittstellen)

F # unterstützt direkt gegenseitig rekursive Typen. Betrachten Sie die folgende Huhn / Ei-Typ-Definition:

type Chicken =
   | Eggs of Egg list
and Egg =
   | Chickens of Chicken list

Der Punkt ist, dass wechselseitig rekursive Typen zusammen erklärt werden unter Verwendung des ‚und‘ Bediener (im Gegensatz zu zwei getrennten Typen)

Wie wäre es DAOMisc.FindIdByType beseitigen, und es mit einem FindId innerhalb jeder DAO-Klasse zu ersetzen? FindId würde nur wissen, wie man seine eigene Art zu finden. Dies würde die Notwendigkeit für die Basisklasse und dynamische Typprüfung und die zirkuläre Abhängigkeit zwischen DAOMisc und alle anderen DAO-Klassen beseitigen. DAO-Typen können auf Miteinandersein abhängen, so CityDAO kann StateDAO.FindId nennen. (DAO-Typ auf einem für beiden Seiten eines anderen abhängen könnte, wenn nötig.)

Ist das, was Sie reden, wenn Sie sagte: „Der einfache Ansatz, um diese Funktion in jedem DAO zu setzen wäre ... Aber das kommt mir genauso falsch ...“? Ich bin nicht sicher, weil Sie gesagt haben, dass die Funktion nur auf die Typen beziehen würde, die, bevor sie kommen. Die Idee, dass ich hier vorstelle, dass jede FindId Funktion nur seine eigene Art kennt.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top