Domanda

Ho alcuni tipi che si estendono un tipo comune, e questi sono i miei modelli.

Poi ho tipi DAO per ogni tipo di modello per le operazioni CRUD.

Ora ho bisogno di una funzione che mi permetterà di trovare un id dato alcun tipo di modello, così ho creato un nuovo tipo per alcune funzioni varie.

Il problema è che non so come ordinare questi tipi. Attualmente ho modelli prima dao, ma in qualche modo ho bisogno DAOMisc prima CityDAO e CityDAO prima DAOMisc, che non è possibile.

L'approccio semplice sarebbe quello di mettere questa funzione in ogni DAO, riferendosi ai soli tipi che possono venire prima di esso, così, State viene prima City come State ha una relazione di chiave esterna con City, quindi la funzione ausiliaria sarebbe molto corto. Ma, questo solo mi sembra sbagliato, quindi non sono certo come meglio affrontare questo.

Ecco il mio vario tipo, in cui BaseType è un tipo comune per tutti i miei modelli.

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

Ecco un tipo dao. CommonDAO ha effettivamente il codice per le operazioni CRUD, ma che non è importante qui.

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
    )

Questo è il mio tipo di modello:

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);]

Lo scopo di questa funzione è che FindIdByType voglio trovare l'id di una relazione di chiave esterna, in modo da poter impostare il valore nel mio modello e quindi avere la CRUD funzioni fanno le operazioni con tutte le informazioni corrette. Così, City ha bisogno l'ID per il nome dello stato, quindi vorrei ottenere il nome dello stato, lo mise nel tipo state, quindi chiamare questa funzione per ottenere l'ID per quello stato, quindi il mio inserto città includerà anche l'ID per l'estero chiave.

Questo sembra essere l'approccio migliore, in modo molto generico per inserti maniglia, che è l'attuale problema che sto cercando di risolvere.

UPDATE:

Ho bisogno di ricerca e vedere se posso in qualche modo iniettare il metodo FindIdByType nella CommonDAO dopo tutte le altre DAO sono stati definiti, quasi come se si tratta di una chiusura. Se questo è stato Java vorrei utilizzare AOP per ottenere la funzionalità che sto cercando, non certo come fare questo in F #.

Finale Aggiornamento:

Dopo pensare al mio approccio ho capito che era fatalmente incrinata, così mi si avvicinò con un approccio diverso.

Ecco come farò un inserto, e ho deciso di mettere questa idea in ogni classe di entità, che è probabilmente una migliore idea.

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

Non ho iniziato ad usare il fklist ancora, ma è int list e so che nome della colonna va con ciascuno di essi, quindi ho solo bisogno di fare inner join per seleziona, per esempio.

Questo è il tipo di base inserto che è generalizzato:

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

Sarebbe bello se F # poteva fare co / contra-varianza, così ho dovuto aggirare questa limitazione.

È stato utile?

Soluzione

Questo esempio è molto lontano da quello che sono abituato a nella programmazione funzionale. Ma per il problema di ordinare tipi mutuamente ricorsivi, c'è una soluzione standard: parametri del tipo di utilizzo e rendere tipi due livelli. Vi darò un esempio semplice in OCaml, una lingua correlata. Non so come tradurre l'esempio semplice nelle funzioni di tipo spaventosi che si sta utilizzando.

Ecco ciò che non funziona:

type misc = State of string
          | City  of city

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

Ecco come risolvere il problema con i tipi a due livelli:

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

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

Questo esempio è OCaml, ma forse si può generalizzata a F #. Spero che sia di aiuto.

Altri suggerimenti

In F #, è possibile definire tipi mutuamente ricorsivi , che è, è possibile definire i due tipi che hanno bisogno di riferimento tra loro insieme e vedranno l'un l'altro. La sintassi per la scrittura di questo è:

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

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

Il limite di questa sintassi è che entrambi i tipi devono essere dichiarate in un unico file, quindi non è possibile utilizzare la tipica C # organizzazione 1 tipo di file per 1.

Come Norman fa notare, questo non è un tipico design funzionale, per cui se avete progettato tutto lo strato di accesso ai dati in maniera più funzionale, probabilmente si potrebbe evitare questo problema. Tuttavia, direi che non c'è niente di sbagliato con che combina lo stile funzionale e orientato agli oggetti in F #, in modo da utilizzare i tipi mutuamente ricorsivi può essere l'unica opzione.

È probabilmente può scrivere il codice più bene se si definisce prima interfacce per i due tipi - questi possono essere o non hanno bisogno di essere reciprocamente ricorsivo (a seconda se si è utilizzato nell'interfaccia pubblica dell'altro):

type ICityDAO = 
  abstract Foo : // ...

type IDAOMisc = 
  abstract Foo : // ...

Questo ha i seguenti vantaggi:

  • La definizione di tutte le interfacce reciprocamente ricorsive in un singolo file non rendere il codice meno leggibile
  • È possibile poi fare riferimento alle interfacce, in modo che nessun altro tipo devono essere reciprocamente ricorsivo
  • Come effetto collaterale, avrete il codice più estensibile (grazie a interfacce)

F # supporta direttamente i tipi mutuamente ricorsivi. Si consideri la seguente definizione del tipo di pollo / uova:

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

Il punto è che i tipi mutuamente ricorsivi sono dichiarati insieme utilizzando l'operatore 'e' (al contrario di due tipi distinti)

Come di eliminare DAOMisc.FindIdByType, e la sua sostituzione con un FindId all'interno di ogni classe DAO? FindId saprebbe solo come trovare il proprio tipo. Questo eliminerebbe la necessità per la classe di base e prova di tipo dinamico, e la dipendenza circolare tra DAOMisc e tutte le altre classi DAO. tipi DAO possono dipendere da un altro, in modo CityDAO può chiamare StateDAO.FindId. (Tipi DAO potrebbero dipendono vicendevolmente, se necessario.)

E 'questo quello che stavi parlando quando hai detto, "L'approccio semplice sarebbe quello di mettere questa funzione in ogni DAO ... Ma, questo solo mi sembra sbagliato ..."? Io non sono sicuro perché lei ha detto che la funzione si riferisce solo ai tipi che vengono prima di esso. L'idea che sto presentando qui è che ogni funzione FindId conosce solo il proprio tipo.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top