سؤال

لدي بعض الأنواع التي تمد نوعًا مشتركًا ، وهذه هي طرفي.

بعد ذلك لدي أنواع DAO لكل نوع من أنواع النماذج لعمليات CRUD.

لدي الآن حاجة إلى وظيفة تسمح لي بالعثور على معرف يعطى أي نوع من الطراز ، لذلك قمت بإنشاء نوع جديد لبعض الوظائف المتنوعة.

المشكلة هي أنني لا أعرف كيفية طلب هذه الأنواع. حاليا لدي نماذج قبل داو ، لكنني بحاجة بطريقة أو بأخرى DAOMisc قبل CityDAO و CityDAO قبل DAOMisc, ، وهو أمر غير ممكن.

سيكون النهج البسيط هو وضع هذه الوظيفة في كل DAO ، في إشارة إلى الأنواع التي يمكن أن تأتي قبلها ، لذلك ، State يأتي قبل City كما State له علاقة مفتاح خارجي مع City, ، وبالتالي فإن الوظيفة المتنوعة ستكون قصيرة جدا. لكن هذا يذهلني تمامًا ، لذلك لست متأكدًا من أفضل طريقة لكي أتعامل مع هذا.

هذا هو نوعي المتنوع ، حيث BaseType هو نوع شائع لجميع النماذج الخاصة بي.

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

هنا نوع واحد داو. CommonDAO في الواقع لديه رمز عمليات CRUD ، ولكن هذا ليس مهمًا هنا.

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
    )

هذا نوع النموذج الخاص بي:

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

الغرض من هذا FindIdByType الوظيفة هي أنني أرغب في العثور على المعرف لعلاقة مفتاح خارجي ، لذلك يمكنني تعيين القيمة في النموذج الخاص بي ثم جعل وظائف CRUD تقوم بالعمليات مع جميع المعلومات الصحيحة. لذا، City يحتاج إلى معرف اسم الدولة ، لذلك سأحصل على اسم الولاية ، وأضعه في state اكتب ، ثم اتصل بهذه الوظيفة للحصول على المعرف لتلك الولاية ، لذلك ستتضمن إدراج مدينتي أيضًا معرف المفتاح الخارجي.

يبدو أن هذا هو أفضل طريقة ، بطريقة عامة للغاية للتعامل مع الإدراج ، وهي المشكلة الحالية التي أحاول حلها.

تحديث:

أحتاج إلى البحث ومعرفة ما إذا كان بإمكاني حقن طريقة FindIdbyType بطريقة ما في Commondao بعد تعريف جميع DAO الأخرى ، كما لو كان الإغلاق. إذا كان هذا هو Java ، فسأستخدم AOP للحصول على الوظيفة التي أبحث عنها ، لست متأكدًا من كيفية القيام بذلك في F#.

التحديث النهائي:

بعد التفكير في مقاربي ، أدركت أنه معيب بشكل قاتل ، لذلك توصلت إلى نهج مختلف.

هذه هي الطريقة التي سأفعل بها إدراجًا ، وقررت وضع هذه الفكرة في كل فصل كيان ، والتي ربما تكون فكرة أفضل.

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

لم أبدأ في استخدام fklist ومع ذلك ، لكنه كذلك int list وأنا أعلم أي اسم عمود يذهب مع كل اسم واحد ، لذلك أنا فقط بحاجة إلى القيام به inner join للاختيار ، على سبيل المثال.

هذا هو إدراج النوع الأساسي المعمم:

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

سيكون من الرائع إذا كان بإمكان F# القيام بالتهوية CO/Contra ، لذلك اضطررت إلى العمل حول هذا القيد.

هل كانت مفيدة؟

المحلول

هذا المثال بعيد جدًا عما اعتدت عليه في البرمجة الوظيفية. ولكن بالنسبة لمشكلة طلب أنواع العودية المتبادلة ، هناك حل قياسي: استخدم معلمات النوع وصنع أنواعًا من المستوى. سأقدم مثالًا بسيطًا في OCAML ، لغة ذات صلة. لا أعرف كيفية ترجمة المثال البسيط إلى وظائف النوع المخيف الذي تستخدمه.

هذا ما لا يعمل:

type misc = State of string
          | City  of city

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

إليك كيفية إصلاحها بنوعين من المستويين:

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

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

هذا المثال هو OCAML ، ولكن ربما يمكنك التعميم على F#. أتمنى أن يساعدك هذا.

نصائح أخرى

في F#، من الممكن تحديد أنواع العودية المتبادلة, ، أي أنه يمكنك تحديد النوعين اللذين يحتاجان إلى الرجوع إلى بعضهما البعض وسوف يرون بعضهم البعض. بناء الجملة لكتابة هذا هو:

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

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

يتمثل الحد من هذا الجملة في أنه يجب الإعلان عن كلا النوعين في ملف واحد ، لذلك لا يمكنك استخدام نوع C# Organization 1 النموذجي لكل ملف.

كما يشير نورمان ، هذا ليس تصميمًا وظيفيًا نموذجيًا ، لذلك إذا قمت بتصميم طبقة الوصول إلى البيانات بأكملها بطريقة أكثر فاعلية ، فربما يمكنك تجنب هذه المشكلة. ومع ذلك ، أود أن أقول أنه لا حرج في الجمع بين النمط الوظيفي والموجهة نحو الكائن في F#، لذلك قد يكون استخدام أنواع العودية المتبادلة هو الخيار الوحيد.

من المحتمل أن تكتب الرمز بشكل جيد أكثر إذا قمت أولاً بتحديد واجهات للنوعين - قد تحتاج إلى أن تكون أو لا تحتاج إلى عودية متبادلة (اعتمادًا على ما إذا كان يتم استخدامه في الواجهة العامة للآخر):

type ICityDAO = 
  abstract Foo : // ...

type IDAOMisc = 
  abstract Foo : // ...

هذا له الفوائد التالية:

  • تحديد جميع الواجهات العودية المتبادلة في ملف واحد لا يجعل الكود أقل قابلية للقراءة
  • يمكنك لاحقًا الرجوع إلى الواجهات ، لذلك لا يلزم أن تكون هناك أنواع أخرى متكررة بشكل متبادل
  • كنتيجة جانبية ، سيكون لديك رمز أكثر قابلية للتمديد (بفضل الواجهات)

F# يدعم مباشرة أنواع العودية المتبادلة. النظر في تعريف الدجاج/البيض التالي:

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

النقطة المهمة هي أن الأنواع المتكررة المتبادلة يتم الإعلان عنها معًا باستخدام المشغل "و" (على عكس نوعين منفصلين)

ماذا عن القضاء على daomisc.findidbytype ، واستبداله بـ findid داخل كل فئة DAO؟ ستعرف Findid فقط كيفية العثور على نوعه الخاص. هذا من شأنه أن يلغي الحاجة إلى الفئة الأساسية واختبار النوع الديناميكي ، والاعتماد الدائري بين DAOMISC وجميع فئات DAO الأخرى. يمكن أن تعتمد أنواع DAO على أحدهما الآخر ، بحيث يمكن لـ Citydao الاتصال بـ attedao.findid. (يمكن أن تعتمد أنواع DAO على بعضها البعض بشكل متبادل ، إذا لزم الأمر.)

هل هذا ما كنت تتحدث عنه عندما قلت ، "النهج البسيط هو وضع هذه الوظيفة في كل داو ... ولكن هذا يذهلني فقط مخطئًا ..."؟ لست متأكدًا لأنك قلت إن الوظيفة ستشير فقط إلى الأنواع التي تأتي قبلها. فكرة تقديمها هنا هي أن كل وظيفة FindId تعرف فقط نوعها الخاص.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top