gpt4 book ai didi

entity-framework - 使用 Fluent API 定义 Entity Framework 键

转载 作者:行者123 更新时间:2023-12-04 08:35:48 25 4
gpt4 key购买 nike

我正在尝试为具有两个关键属性的模型类型定义一个键,并且定义如下:

type Model () =
member val IdOne = 0 with get, set
member val IdTwo = 0 with get, set
member val OtherProperty = "" with get, set

当我尝试在 Entity Framework 5 中使用此模型时,出现“模型未定义键。为此 EntityType 定义键”的错误。给出了模型类型,我无法更改它们并添加 [<Key>]属性。所以我尝试了 Fluent API。

在 C# 中,你会做这样的事情:
modelBuilder.Entity<Model>().HasKey(m => new { m.IdOne, m.IdTwo });

它使用匿名类型。但是对于我的生活,我无法弄清楚如何在 F# 中实现这一点。我尝试了元组、记录,甚至是具有 IdOne 和 IdTwo 属性的常规类型:
// Regular type with properties IdOne & IdTwo.
type ModelKey (idOne, idTwo) =
member this.IdOne = idOne
member this.IdTwo = idTwo
modelBuilder.Entity<Model>().HasKey(fun (m : Model) -> ModelKey (m.IdOne, m.IdTwo))
// ArgumentNullException: Value cannot be null. Parameter name: source

// Regular type with default constructor and properties IdOne & IdTwo.
type ModelKey2 () =
member val IdOne = 0 with get, set
member val IdTwo = 0 with get, set
modelBuilder.Entity<Model>().HasKey(fun (m : Model) -> ModelKey2 ())
// ArgumentNullException: Value cannot be null. Parameter name: source

// Record type.
type ModelKeyRecord = { IdOne : Int32; IdTwo : Int32 }
modelBuilder.Entity<Model>().HasKey(fun (m : Model) -> { IdOne = m.IdOne; IdTwo = m.IdTwo })
// ArgumentNullException: Value cannot be null. Parameter name: source

// Tuple.
modelBuilder.Entity<Model>().HasKey(fun (m : Model) -> (m.IdOne, m.IdTwo))
// ArgumentNullException: Value cannot be null. Parameter name: source

这些方法都不起作用,我每次都会收到 ArgumentNullException。我没有想法了...

编辑
使用下面提供的代码 Tomas(顺便说一下,这会导致相同的 ArgumentNullException),我做了一些窥探。这是我发现的:

我使用下面的函数来分析 C# 正在构建的表达式树:
static void Analyze<T>(Expression<Func<Model, T>> function)
{
}

// Call it like this:
Analyze(m => new { m.IdOne, m.IdTwo });

然后我在调试器中查看了生成的 lambda。这是 C# 生成的:
{m => new <>f__AnonymousType0'2(IdOne = m.IdOne, IdTwo = m.IdTwo)}

使用 Tomas 的 getFuncTree 函数在 F# 端做同样的事情,使用 <@ fun (m : Model) -> ModelKey(m.IdOne, m.IdTwo) @>产量:
{m => new ModelKey(m.IdOne, m.IdTwo)}

如您所见,F# 代码中缺少参数的显式命名(无论如何,这看起来像属性)。我在 F# 中手动重新创建了整个表达式树,使其看起来像 C# 版本:
let modelKeyExpression =
Expression.Lambda<Func<Model, ModelKey>> (
body = Expression.New (
``constructor`` = typeof<ModelKey>.GetConstructor [| typeof<Int32>; typeof<Int32> |],
arguments = seq {
yield Expression.MakeMemberAccess (
expression = Expression.Parameter (
``type`` = typeof<Model>,
name = "m"
),
``member`` = typeof<Model>.GetProperty "IdOne"
) :> Expression;
yield Expression.MakeMemberAccess (
expression = Expression.Parameter (
``type`` = typeof<Model>,
name = "m"
),
``member`` = typeof<Model>.GetProperty "IdTwo"
) :> Expression
},
members = seq {
yield (typeof<ModelKey>.GetProperty "IdOne") :> MemberInfo
yield (typeof<ModelKey>.GetProperty "IdTwo") :> MemberInfo
}
),
parameters = [
Expression.Parameter (
``type`` = typeof<Model>,
name = "m"
)
]
)

F# 表示中缺少的部分是成员序列。
当我将鼠标移到这个表达式上时,这个表示出现:
{m => new ModelKey(IdOne = m.IdOne, IdTwo = m.IdTwo)}

如您所见,除了类之外,它看起来是一样的。但是当我尝试在 HasKey 中使用这个表达式时方法,我得到以下 InvalidOperationException :
The properties expression 'm => new ModelKey(IdOne = m.IdOne, IdTwo= m.IdTwo)'
is not valid. The expression should represent a property: C#: 't =>
t.MyProperty' VB.Net: 'Function(t) t.MyProperty'. When specifying multiple
properties use an anonymous type: C#: 't => new { t.MyProperty1,
t.MyProperty2 }' VB.Net: 'Function(t) New With { t.MyProperty1,
t.MyProperty2 }'.

所以在我看来,这个匿名类语法做了一些特别的事情......

最佳答案

在 F# 4.6 中,经过多次努力,这对我有用。

显然,您只需要一个元组。这是有道理的,因为没有明确成员名称的匿名对象基本上是一个元组。

我不敢相信没有人把它放在 MS 文档上。

    modelBuilder.Entity<Entity>()
.HasKey(fun e -> (e.Key1, e.Key2) :> obj)
|> ignore

关于entity-framework - 使用 Fluent API 定义 Entity Framework 键,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18381683/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com