Pregunta

Tengo algunos tipos que se extienden un tipo común, y estos son mis modelos.

I a continuación, tienen tipos de DAO para cada tipo de modelo para las operaciones CRUD.

Ahora tengo una necesidad de una función que permitirá que encuentre un identificador dado ningún tipo de modelo, así que creé un nuevo tipo para algunas funciones auxiliares.

El problema es que no sé cómo ordenar este tipo. Actualmente tengo modelos antes DAO, pero de alguna manera necesito DAOMisc antes CityDAO y CityDAO antes DAOMisc, que no es posible.

El enfoque simple sería poner esta función en cada DAO, refiriéndose sólo a los tipos que pueden venir antes de que, así, State viene antes City como State tiene una relación de clave externa con City, por lo que la función auxiliar sería muy corto. Sin embargo, esto sólo me parece mal, así que no estoy seguro de cómo mejor abordar este.

Esta es mi tipo misceláneo, donde BaseType es un tipo común de todos mis modelos.

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

Aquí es un tipo DAO. CommonDAO en realidad tiene el código para las operaciones CRUD, pero eso no es importante en este caso.

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
    )

Este es mi tipo de modelo:

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

El propósito de esta función es que FindIdByType Quiero encontrar el id de una relación de clave externa, por lo que puede establecer el valor en mi modelo y luego tener la ABM funciones hacen las operaciones con toda la información correcta. Así, City necesita el identificador para el nombre del estado, por lo que me gustaría tener el nombre del estado, lo puso en el tipo state, a continuación, llamar a esta función para obtener el identificador para ese estado, por lo que mi inserción ciudad también incluirá el identificador para el extranjero la clave.

Esto parece ser el mejor enfoque, de una manera muy genérica a los insertos de mango, que es el problema actual que estoy tratando de resolver.

ACTUALIZACIÓN:

Me necesidad de investigar y ver si hay algún modo de inyección se han definido el método FindIdByType en el CommonDAO después de todos los demás DAOs, casi como si se trata de un cierre. Si se trataba de Java usaría AOP para obtener la funcionalidad Busco, sin saber cómo hacer esto en C #.

Actualización Final:

Después de pensar en mi enfoque me di cuenta que era defectuoso fatalmente, por lo que me ocurrió con un enfoque diferente.

Esta es la forma en que haré una inserción, y decidí poner esta idea en cada clase de entidad, que es probablemente una mejor idea.

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

No han comenzado a utilizar la fklist todavía, pero es int list y sé qué nombre de la columna corresponde a cada uno, así que sólo hay que hacer para inner join selecciona, por ejemplo.

Este es el inserto de tipo de base que se generaliza:

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

Sería bueno si F # podía hacer co / contra-varianza, por lo que tenía que trabajar en torno a esa limitación.

¿Fue útil?

Solución

Este ejemplo está muy lejos de lo que estoy acostumbrado en la programación funcional. Sin embargo, para el problema de ordenar tipos mutuamente recursivos, hay una solución estándar: parámetros de tipo de uso y crea tipos de dos niveles. Voy a dar un ejemplo sencillo en OCaml, una lengua relacionada. No sé cómo traducir el ejemplo simple en las funciones de tipo de miedo que está utilizando.

Esto es lo que no funciona:

type misc = State of string
          | City  of city

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

Así es como lo arreglas con los tipos de dos niveles:

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

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

Este ejemplo es OCaml, pero tal vez usted puede generalizarse a F #. Espero que esto ayude.

Otros consejos

En F #, es posible definir tipos mutuamente recursivos , es decir, se pueden definir los dos tipos que se necesita hacer referencia entre sí juntos y van a ver unos a otros. La sintaxis para escribir esto es:

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

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

La limitación de esta sintaxis es que los dos tipos tienen que ser declarada en un solo archivo, por lo que no puede utilizar la típica organización C # 1 por 1 Tipo de archivo.

Como Norman señala, esto no es un típico diseño funcional, por lo que si usted diseñó toda la capa de acceso a datos de una manera más funcional, que probablemente se podría evitar este problema. Sin embargo, yo diría que no hay nada malo con la combinación de estilo funcional y orientada a objetos en C #, por lo que el uso de tipos mutuamente recursivos puede ser la única opción.

Es probable que pueda escribir el código sea más agradable si se define primero las interfaces para los dos tipos - estos pueden o no deben ser mutuamente recursivo (dependiendo de si se emplea en la interfaz pública de la otra):

type ICityDAO = 
  abstract Foo : // ...

type IDAOMisc = 
  abstract Foo : // ...

Esto tiene las siguientes ventajas:

  • Definición de todas las interfaces mutuamente recursivas en un solo archivo no hace que el código sea menos legible
  • Usted puede referirse más tarde a las interfaces, por lo que no hay otros tipos tienen que ser mutuamente recursivo
  • Como efecto secundario, tendrá código más extensible (gracias a las interfaces)

F # apoya directamente tipos mutuamente recursivos. Considere la siguiente definición de tipo de pollo / huevo:

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

El punto es que los tipos mutuamente recursivos se declaran juntos utilizando la 'y' operador (en contraposición a dos tipos separados)

¿Qué hay de eliminar DAOMisc.FindIdByType, y su sustitución por una FindId dentro de cada clase DAO? FindId sólo saber cómo encontrar su propio tipo. Esto eliminaría la necesidad de que la clase base y la prueba de tipo dinámico, y la dependencia circular entre DAOMisc y todas las otras clases DAO. tipos DAO pueden depender de una sola otra, por lo CityDAO puede llamar StateDAO.FindId. (Tipos DAO podría depender de uno al otro mutuamente, si es necesario.)

¿Es esto lo que estaba hablando cuando dijo, "El enfoque simple sería poner esta función en cada DAO ... Pero, esto sólo me parece mal ..."? No estoy seguro porque usted dijo que la función se referiría sólo a los tipos que se presentan ante él. La idea de que estoy presentando aquí es que cada función FindId sólo conoce su propio tipo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top