I've got following class defined in F#, with mapping attributes for Linq to SQL:
[<Table(Name="Expense")>]
type public Expense(datetime : Nullable<DateTime>, value, category, comment) =
let mutable id = 0
let mutable datetime = if datetime.HasValue then datetime.Value else DateTime.Now
let mutable value = value
let mutable category = category
let mutable comment = comment
[<Column(IsPrimaryKey=true, IsDbGenerated=true, AutoSync=AutoSync.OnInsert)>]
member x.ExpenseID with get() = id and set v = id <- v
[<Column>]
member x.DateTime with get() = datetime and set v = datetime <- v
[<Column>]
member x.Value with get() = value and set v = value <- v
[<Column>]
member x.Category with get() = category and set v = category <- v
[<Column>]
member x.Comment with get() = comment and set v = comment <- v
new() = Expense(nl, 0m, "", "")
Then I want to insert new object of that type, using following code (fragment):
member private x.expenses = (new DataContext(connString)).GetTable<Expense>()
member x.Add (expense : Expense) =
x.expenses.InsertOnSubmit(expense)
x.expenses.Context.SubmitChanges()
Calling SubmitChanges() doesn't do anything, nor any exception is thrown. So I tried to check, if there is something with it being an F# object, and I've declared other class in C#, with exactly same mappings. Then I was able to insert new record. Now I'm wondering, what's the difference?
Did some Reflector investigation, the only difference are attributes [CompilerGenerated] on C# auto getters/setters, and [Serializable] and CompilationMapping(SourceConstructFlags.ObjectType)] on F# class...could it be one of those?
Reflector disassemblies: http://pastebin.com/qTRfVcmm
// EDIT
By doing some debugging against .NET framework code, I've noticed that internal list of tracked objects of the DataContext instance is not consistent between InsertOnSubmit and SubmitChanges call. At the beginning of the SubmitChanges call, this list is empty. That led me to thinking, those two references are not targeting same DataContext instance, and VS debugger confirmed that. Still, no idea why.
The problem is the first use of member. F# members (without paramaters) behave like properties, so you're creating new data context each time you access x.expenses. To correct that, you can store the table object in a field using let:
type SomeType() =
let expenses = (new DataContext(connString)).GetTable<Expense>()
member x.Add (expense : Expense) =
expenses.InsertOnSubmit(expense)
expenses.Context.SubmitChanges()
The member x.Foo = <expr> syntax in F# corresponds to a property with getter, so in the C# syntax, your original code would look like this:
Table<Expenses> Expenses {
get { return (new DataContext(connString)).GetTable<Expense>(); }
}
...which explains why there were multiple copies of the data context created.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With