Saving record in RavenDb with F# adding extra Id column - f#

When I save a new F# Record, I'm getting an extra column called Id# in the RavenDb document, and it shows up when I load or view the object in code; it's even being converted to JSON through my F# API.
Here is my F# record type:
type Campaign = { mutable Id : string; name : string; description : string }
I'm not doing anything very exciting to save it:
let save c : Campaign =
use session = store.OpenSession()
session.Store(c)
session.SaveChanges()
c
Saving a new instance of a record creates a document with the Id of campaigns/289. Here is the full value of the document in RavenDb:
{
"Id#": "campaigns/289",
"name": "Recreating Id bug",
"description": "Hello StackOverflow!"
}
Now, when I used this same database (and document) in C#, I didn't get the extra Id# value. This is what a record looks like when I saved it in C#:
{
"Description": "Hello StackOverflow!",
"Name": "Look this worked fine",
}
(Aside - "name" vs "Name" means I have 2 name columns in my document. I understand that problem, at least).
So my question is: How do I get rid of the extra Id# property being created when I save an F# record in RavenDb?

As noted by Fyodor, this is caused by how F# generates a backing field when you create a record type. The default contract resolver for RavenDB serializes that backing field instead of the public property.
You can change the default contract resolver in ravendb. It will look something like this if you want to use the Newtonsoft Json.Net:
DocumentStore.Conventions.JsonContractResolver <- new CamelCasePropertyNamesContractResolver()
There is an explanation for why this works here (see the section titled: "The explanation"). Briefly, the Newtonsoft library uses the public properties of the type instead of the private backing fields.
I also recommend, instead of having the mutable property on the Id, you can put the [<CLIMutable>] attribute on the type itself like:
[<CLIMutable>]
type Campaign = { Id : string; name : string; description : string }
This makes it so libraries can mutate the values while preventing it in your code.

This is a combination of... well, you can't quite call them "bugs", so let's say "non-straightforward features" in both F# compiler and RavenDb.
The F# compiler generates a public backing field for the Id record field. This field is named Id# (a standard pattern for all F# backing fields), and it's public, because the record field is mutable. For immutable record fields, backing fields will be internal. Why it needs to generate a public backing field for mutable record fields, I don't know.
Now, RavenDb, when generating the schema, apparently looks at both properties and fields. This is a bit non-standard. The usual practice is to consider only properties. But alas, Raven picks up the public field named Id#, and makes it part of the schema.
You can combat this problem in two ways:
First, you could make the Id field immutable. I'm not sure whether that would work for you or RavenDb. Perhaps not, since the Id is probably generated on insert.
Second, you could declare your Campaign not as an F# record, but as a true class:
type Campaign( id: int, name: string, description: string ) =
member val Id = id with get, set
member val name = name
member val description = description
This way, all backing fields stay internal and no confusion will arise. The drawback is that you have to write every field twice: first as constructor argument, then as class member.

Related

How to derive record types in F#?

I'm inserting data into Azure CosmosDB via FSharp.ComosDb. Here is the record type that I write in the DB:
[<CLIMutable>]
type DbType =
{ id: Guid
Question: string
Answer: int }
The persistence layer works fine but I face an inelegant redundancy. The record I'm inserting originates from the Data Transfer Object (DTO) with the following shape:
type DataType =
{ QuestionId: Guid
Question: string
Answer: int }
CosmosDb accepts only records with a lowercase id. Is there any way to derive the DbType from DataType or I have to define DbType from scratch?
Is there anything a la copy and update record expression record2 = { record1 with id = record1.QuestionId } but at the type level?
There's no type-level way of deriving one record type from another the way you describe, you can however get reasonably close with the addition of anonymous records in F# 4.6.
type DataType =
{ QuestionId: Guid
Question: string
Answer: int }
let example =
{ QuestionId = Guid.NewGuid()
Question = "The meaning of life etc."
Answer = 42 }
let extended =
{| example with id = example.QuestionId |}
This gives you a value of an anonymous record type with an added field, and may be well suited to your scenario, however it's unwieldy to write code against such type once it leaves the scope of the function you create it in.
If all you care is how this single field is named - serialization libraries usually have ways of providing aliases for field names (like Newtonsoft.Json's JsonProperty attribute). Note that this might be obscured from you by the CosmosDb library you're using, which I'm not familiar with.
Another more involved approach is to use generic envelope types so that the records you persist have a uniform data store specific header across your application:
type Envelope<'record> =
{
id: string
// <other fields as needed>
payload: 'record
}
In that case the envelope contains the fields that your datastore expects to be there to fulfill the contract (+ any application specific metadata you might find useful, like timestamps, event types, versions, whatnot) and spares you the effort of defining data store specific versions of each type you want to persist.
Note that it is still a good idea in general to decouple the internal domain types from the representation you use for storage for maintainability reasons.

Avro schema: adding a new field with default value - straight default value or a union with null?

So I have an avro record like so (call it v1):
record MyRecord {
array<string> keywords;
}
I'd like to add a field caseSensitive with a default value of false (call it v2). The first approach I have is:
record MyRecord {
array<string> keywords;
boolean caseSensitive = false;
}
According to schema evolution, this is both backward and forward compatible because a reader with the new schema v2 reading a record that was encoded with old writer schema v1 will be able to fill this field with the default value and a reader with older schema v1 will be able to read a record encoded with the new writer schema v2 because it will just ignore the newly added field.
Another way to add this field is by adding a union type of null and boolean with a default value of null, like so:
record MyRecord {
array<string> keywords;
union{null, boolean} caseSensitive = null;
}
This is also backward and forward compatible. I can see that sometimes one would want to use the 2nd approach if there is no clear default value for a field (such as name, address, etc.). But given my use case with a clear default value, I'm thinking of going with the first solution. My question is: is there any other concerns that I'm missing here?
There will be a potential issue with writers in the first case--apparently writers do not use default values. So a writer writing "old data" (missing the new field--so writer is publishing a record with the "keywords" field only) will blow up against the first schema. Same writer using second schema will be successful, and the "caseSensitive" field will be set to null in the resulting message.

F# Turning XmlProvider data into Records

I am pulling in some XML data using XmlProvider, and I will be accessing it from C#. As you can't use type provided fields directly from C#, I need create record out of them. I can do this by hand but I believe this should be possible to automate using reflection. If I create record types with the same names and types as the fields in the type provider, I should be able to use something like FSharpValue.MakeRecord(typeof<MyType>,values) where values is an array of objects.
What I don't know is how to get the array of values out of the type provider, and how to handle nested records, for instance:
type Address =
{
Address1 : string
City : string
State : string
}
type Client =
{
Id : int
FullName : string
Address : Address
}
In this case Client contains one Address. Will I need to walk the tree and use MakeRecord on the leaves and work my way up?
If you're willing to hand code the types, why do you need the type provider in the first place?
If you're doing some additional logic on F# side, you'll have no choice but to create the records manually anyway. And if you're not doing anything, you can just use the .NET out of the box serializer (or another library) to create them from xml.

BreezeManager doesn't track changes with extended properties

I extended my server entity with some properties in the client side .
When getting data from the query I really see these properties in the result filled with the proper values .
When I change a value of an extended properties the manager doesn't track this change .
When I call manager.rejectChanges() no action is happen , I debugged the code and I see in the entityAspect.entityState ("Unchaged") although I modified the property.
If I modify a property comes from the server entity every thing is ok.
Here is my Product entity in the server :
public class Product
{
public string Code {get;set;}
}
I extended the product in the client side with some others :
var Product = function () {
this.kind = ko.observable();
};
breeze.metadataStore.registerEntityTypeCtor("Product", Product);
After the query I get both field (Code , Kind) , if I change Code , entity state is modified , I can call manager.rejectChanges and its takes effect, but if I change kind nothing happen , the entity state is "Unchaged".
Any idea why this happen ?
Thanks in advance ...
By "extended" I assume you mean "unmapped" properties which are typically defined in a custom constructor as described in "Extending Entities"
"Unmapped" properties do not map to permanently stored values on the server. Therefore, changes to unmapped properties do not affect EntityState and they are not sent to the server.
Note that the server can supply the value of an unmapped property in the payload of a query and Breeze will set the unmapped property accordingly. This is a way to calculate non-persisted values on the server and transmit them to the entity on the client.
On the client an unmapped property behaves in other respects like a mapped property:
conforms to the syntax of the model library (e.g., it becomes an observable in KO models)
serialized when exported
validation rules apply
raises propertyChange when the value is changed
entity remembers the property's "original value"
rejectChanges() reverts the property to that original value

Objective-C get a class property from string

I've heard a number of similar questions for other languages, but I'm looking for a specific scenario.
My app has a Core Data model called "Record", which has a number of columns/properties like "date, column1 and column2". To keep the programming clean so I can adapt my app to multiple scenarios, input fields are mapped to a Core Data property inside a plist (so for example, I have a string variable called "dataToGet" with a value of 'column1'.
How can I retrieve the property "column1" from the Record class by using the dataToGet variable?
The Key Value Coding mechanism allows you to interact with a class's properties using string representations of the property names. So, for example, if your Record class has a property called column1, you can access that property as follows:
NSString* dataToGet = #"column1";
id value = [myRecord valueForKey:dataToGet];
You can adapt that principle to your specific needs.

Resources