基本 F# / Entity Framework / 泛型函数
Basic F# / Entity Framework / Generic Functions
在开发方面,我是一个完全的初学者,所以对于我对这里术语的不了解,提前表示歉意...
我正在尝试在 SQL 数据库中创建一些非常简单的不相关的 table 来让我的头脑清醒过来。我想使用 Entity Framework 引用这些内容,并且我希望尽可能减少重复。我正在尝试了解是否有更优雅的方法来执行此操作,这样我就不必每次都重新编写 getter 和 setter:
// First open "System; System.Data; System.Data.Entity; System.ComponentModel.DataAnnotations"
// Then define "connectionString"
// Then create two simple classes that have no relation to each other, using CLIMutable
// to help Entity Framework along.
module Model =
[<CLIMutable>] type Customer = {[<Key>]Id: int; FirstName: string; LastName: string;}
[<CLIMutable>] type Item = {[<Key>]Id: int; ItemName: string; ItemDescription: string;}
module Actions =
open Model
type Context() =
inherit DbContext()
[<DefaultValue>] val mutable customers: DbSet<Customer>
member public this.Customers with get() = this.customers
and set v = this.customers <- v
[<DefaultValue>] val mutable items: DbSet<Item>
member public this.Items with get() = this.items
and set v = this.items <- v
// I would like to be able to add several more very simple classes without having to
// repetively type out the getters and setters each time. Ideally I'd like to turn the above
// into a generic function (method? I'm not sure of terminology) that I can call later and
// pass it my desired parameters in terms of table/object names. However, if I move the code
// above the Model and replace DbSet<Customer> with DbSet<'T> this won't work since it won't
// know what type 'T is at this point. I suspect I need a generic function (method?) that
// I can create a new instance of later and replace the generics with actual values (using
// reflection?). Is there any way to do this without making Entity Framework get upset?
let db = new Context()
db.Database.Connection.ConnectionString <- Settings.connectionString
同样,我想创建一个执行 Add() 和 SaveChanges() 步骤的通用函数
下面,但我不确定这是否可行,因为我需要动态替换
'Customers' 或 'Items' 以及我传入的 table 名称 - 以及 't' 的类型
可能会有所不同,具体取决于调用该函数的内容,我不知道是否允许这样做。
let createCustomer id firstName lastName =
let t : Customer = {Id = id;FirstName = firstName; LastName = lastName}
db.Customers.Add(t) |> ignore
db.SaveChanges() |> ignore
let createItem id itemName itemDescription =
let t : Item = {Id = id; ItemName = itemName; ItemDescription = itemDescription}
db.Items.Add(t) |> ignore
db.SaveChanges() |> ignore
open Actions
[<EntryPoint>]
let main argv =
createCustomer 1 "Bob" "Smith"
createItem 1 "First item" "First item test"
Console.ReadLine() |> ignore
0
感谢您的帮助,我的问题可能很基础!
[edit] 非常感谢 Fyodor 提供解决方案。关键是在一般引用 "db" 元素时将“: Context”类型注释添加到它。此外,我犯了一个愚蠢的错误,即在我的主要论点中没有打开 "Model" 模块。更新和工作代码如下:
module Model =
[<CLIMutable>] type Customer = {[<Key>]Id: int; FirstName: string; LastName: string;}
module Actions =
open Model
type Context() =
inherit DbContext()
member val Customers: DbSet<Customer> = null with get, set
let db = new Context()
db.Database.Connection.ConnectionString <- Settings.connectionString
let addAndCommit (db : Context) x =
db.Set().Add x |> ignore
db.SaveChanges() |> ignore
let createCustomer id firstName lastName =
addAndCommit db {Id = id; FirstName = firstName; LastName = lastName}
open Actions
open Model
[<EntryPoint>]
let main argv =
createCustomer 1 "Bob" "Smith"
Console.ReadLine() |> ignore
0
首先, 声明一个带有支持字段的 属性,使用 member val
:
type Context() =
...
member val Customers: DbSet<Customer> = null with get, set
...
其次,访问特定类型的DbSet
,不需要属性。您可以通过DbContext.Set<'t>
方法获取:
let addAndCommit (db: Context) (x: 't) =
db.Set<'t>().Add x |> ignore
db.SaveChanges() |> ignore
let createCustomer id firstName lastName =
addAndCommit db {Id = id; FirstName = firstName; LastName = lastName}
但显式 't
注释并不是真正需要的:F# 可以为您推断。
let addAndCommit (db: Context) x =
db.Set().Add x |> ignore
db.SaveChanges() |> ignore
在开发方面,我是一个完全的初学者,所以对于我对这里术语的不了解,提前表示歉意...
我正在尝试在 SQL 数据库中创建一些非常简单的不相关的 table 来让我的头脑清醒过来。我想使用 Entity Framework 引用这些内容,并且我希望尽可能减少重复。我正在尝试了解是否有更优雅的方法来执行此操作,这样我就不必每次都重新编写 getter 和 setter:
// First open "System; System.Data; System.Data.Entity; System.ComponentModel.DataAnnotations"
// Then define "connectionString"
// Then create two simple classes that have no relation to each other, using CLIMutable
// to help Entity Framework along.
module Model =
[<CLIMutable>] type Customer = {[<Key>]Id: int; FirstName: string; LastName: string;}
[<CLIMutable>] type Item = {[<Key>]Id: int; ItemName: string; ItemDescription: string;}
module Actions =
open Model
type Context() =
inherit DbContext()
[<DefaultValue>] val mutable customers: DbSet<Customer>
member public this.Customers with get() = this.customers
and set v = this.customers <- v
[<DefaultValue>] val mutable items: DbSet<Item>
member public this.Items with get() = this.items
and set v = this.items <- v
// I would like to be able to add several more very simple classes without having to
// repetively type out the getters and setters each time. Ideally I'd like to turn the above
// into a generic function (method? I'm not sure of terminology) that I can call later and
// pass it my desired parameters in terms of table/object names. However, if I move the code
// above the Model and replace DbSet<Customer> with DbSet<'T> this won't work since it won't
// know what type 'T is at this point. I suspect I need a generic function (method?) that
// I can create a new instance of later and replace the generics with actual values (using
// reflection?). Is there any way to do this without making Entity Framework get upset?
let db = new Context()
db.Database.Connection.ConnectionString <- Settings.connectionString
同样,我想创建一个执行 Add() 和 SaveChanges() 步骤的通用函数 下面,但我不确定这是否可行,因为我需要动态替换 'Customers' 或 'Items' 以及我传入的 table 名称 - 以及 't' 的类型 可能会有所不同,具体取决于调用该函数的内容,我不知道是否允许这样做。
let createCustomer id firstName lastName =
let t : Customer = {Id = id;FirstName = firstName; LastName = lastName}
db.Customers.Add(t) |> ignore
db.SaveChanges() |> ignore
let createItem id itemName itemDescription =
let t : Item = {Id = id; ItemName = itemName; ItemDescription = itemDescription}
db.Items.Add(t) |> ignore
db.SaveChanges() |> ignore
open Actions
[<EntryPoint>]
let main argv =
createCustomer 1 "Bob" "Smith"
createItem 1 "First item" "First item test"
Console.ReadLine() |> ignore
0
感谢您的帮助,我的问题可能很基础!
[edit] 非常感谢 Fyodor 提供解决方案。关键是在一般引用 "db" 元素时将“: Context”类型注释添加到它。此外,我犯了一个愚蠢的错误,即在我的主要论点中没有打开 "Model" 模块。更新和工作代码如下:
module Model =
[<CLIMutable>] type Customer = {[<Key>]Id: int; FirstName: string; LastName: string;}
module Actions =
open Model
type Context() =
inherit DbContext()
member val Customers: DbSet<Customer> = null with get, set
let db = new Context()
db.Database.Connection.ConnectionString <- Settings.connectionString
let addAndCommit (db : Context) x =
db.Set().Add x |> ignore
db.SaveChanges() |> ignore
let createCustomer id firstName lastName =
addAndCommit db {Id = id; FirstName = firstName; LastName = lastName}
open Actions
open Model
[<EntryPoint>]
let main argv =
createCustomer 1 "Bob" "Smith"
Console.ReadLine() |> ignore
0
首先, 声明一个带有支持字段的 属性,使用 member val
:
type Context() =
...
member val Customers: DbSet<Customer> = null with get, set
...
其次,访问特定类型的DbSet
,不需要属性。您可以通过DbContext.Set<'t>
方法获取:
let addAndCommit (db: Context) (x: 't) =
db.Set<'t>().Add x |> ignore
db.SaveChanges() |> ignore
let createCustomer id firstName lastName =
addAndCommit db {Id = id; FirstName = firstName; LastName = lastName}
但显式 't
注释并不是真正需要的:F# 可以为您推断。
let addAndCommit (db: Context) x =
db.Set().Add x |> ignore
db.SaveChanges() |> ignore