Shortest syntax for Entity Framework compatible POCO - entity-framework

I need F# to work with Entity Framework seemlesly. I am trying to adapt example from here: https://blogs.msdn.microsoft.com/visualstudio/2011/04/04/f-code-first-development-with-entity-framework-4-1/
The problem is that record declaration is so scary there that it is just unacceptable for me.
type public Car() =
let mutable m_ID : int = 0
let mutable m_name : string = ""
[<Key>]
member public this.ID with get() = m_ID
and set v = m_ID <- v
member public this.Name with get() = m_name
and set v = m_name <- v
I have tried CLIMutable in such a way:
module Program
[<CLIMutable>]
type Car = {
Name:string
}
let c = new Car(Name = "Honda")
It results in error: "No contructors are available for the type 'Car'".
As I understand this answer might be an explanation:
https://stackoverflow.com/a/28845368/585819
I also tried things like:
[<CLIMutable>]
type Car =
{
ID:int
} member this.Name = ""
The error is the same. I feel really disappointed. Can somebody help with this?

The CLIMutable attribute does not have any impact on F# use-sites. The added default constructor is inaccessible from F# user-code and so are mutable properties. If you want to use EFs change tracking (from within F#), records are not a good choice (because you can't change it unless you declare all fields mutable).
If possible consider using e.g. the SQL Provider. On the other hand e.g. Dapper supports serializing/deserializing POCOs and thusly F# records.
As the record looks immutable from F# perspective, regular construction applies:
let c = { Name = "Honda" }
or (to disambiguate, if you also have e.g. type Person = { Name : string })
let c = { Car.Name = "Honda" }
let c : Car = { Name = "Honda" }
let c = { Name = "Honda" } : Car

Here is what seems to be working for me. This is not a record but class. Also it probably could not be named POCO.
//file DataModel.fs
module DataModel
open System.ComponentModel.DataAnnotations
open System.Data.Entity
type Car()=
[<Key>]
member val Id = 0 with get,set
member val Name = "" with get,set
type public CLCars() =
inherit DbContext()
member val Cars: DbSet<Car> = base.Set<Car>() with get,set
//file Program.fs
module Program
open DataModel
let db = new CLCars()
let c = new Car(Name="Honda")
db.Cars.Add(c) |> ignore
db.SaveChanges() |> ignore

Related

Query MongoDB Realm array only at first index

I need to query MongoDB Realm from synced iOS and Android app. In Swift I can write something like this:
let dictionary = realm?.objects(myReamlObject.self)
let results = dictionary?.where {
$0.senses.glosses.term == "the term I want"
}
or using predicate:
let results = dictionary?.filter("ANY senses.glosses.term == %#", "the term I want")
Both work well, but I don't want to check ALL senses.glosses.term.
Every entry has (or could have) many senses and many glosses.
I would like to check term of first senses in first glosses only.
Something I would write like this:
let results = dictionary?.where {
$0.senses[0].glosses[0].term == "the term I want"
}
But it gives error:
Referencing subscript 'subscript(_:)' on 'Query' requires that
'List<myRealmObject_senses>' conform to 'RealmKeyedCollection'
Any suggestion on how to query only first index of an array in MongoDB Realm? Thank you
Let me re-state the question
How to query a Realm objects' List property - but only query on the first
element in the List.
The answer is going to depend on the amount of results being worked with.
Here's how to do it in a way that's O.K. for small datasets but NOT RECOMMENDED
Your models were not included in the question so let me use a simplified model of a PersonClass that as a List of DogClass objects
class PersonClass: Object {
#Persisted var name = ""
#Persisted var dogList = List<DogClass>()
}
class DogClass: Object {
#Persisted var name = ""
}
The idea here is to use Swift high-level functions to only test the first item in each persons doglist for a match (this can be applied to other languages as well)
//get all the people
let peopleResults = realm.objects(PersonClass.self)
//use the high-level Swift function compactMap to return all of
// the people whose first dog is named "Spot"
let persons = peopleResults.compactMap { person -> PersonClass? in
if person.dogList.first?.name == "Spot" {
return person
}
return nil
}
The downside is that this code overrides a fundamental advantage of Realm - that Realm objects are lazily loaded if Realm functions are used e.g. as soon as a high-level Swift function is used, ALL of the objects are loaded into memory, potentially overwhelming the device.
A better option is to simply add a managed property to the PersonClass that also points to the 0'th element in the list.
class PersonClass: Object {
#Persisted var name = ""
#Persisted var dogList = List<DogClass>()
#Persisted var mainDog: DogClass?
func addMainDog(withDog: DogClass) {
self.dogList.append(withDog)
self.mainDog = withDog
}
}
as you can see, there's also a function to add that first dog to the list and also populates the mainDog property which points to the same object. It's one property so the overall impact is very low but the advantages for simple queries are very high.
From there the query becomes trivial
let peopleResults = realm.objects(PersonClass.self).where { $0.mainDog.name == "Spot" }
Expanding on this, you could save the 0th element of each List object in the Parent object or even have a property in each child object that points to the first element in it's respective list.

Why can I create an instance of a static variable?

I have a class that looks like this:
class A {
var aString = ""
static var staticString = ""
}
If I create an instance of A I can't access the static property:
var a = A()
a.staticString = "THIS GIVES AN ERROR"
However, if I create a direct instance to the static variable it works:
var a = A.staticString
a = "THIS WORKS"
The way I understand static variables is that you should only be able to access them directly like this: A.staticString = "hello". But this doesn't seem to be the case.
What's more confusing (to me) is that I can create multiple instances with their own seperate values; that is the value doesn't remain static:
var a = A.staticString
a = "AAA"
var b = A.staticString
b = "BBB"
print(a) //prints AAA
print(b) //prints BBB
Isn't the whole point that a static variable should... remain static? In my head, both a and b should print BBB since b = "BBB" should have overwritten the first value assigned to it.
To make it even more confusing (to me), using a singleton does give me the result I expect:
class A {
static let shared = A()
var aString = ""
static var staticString = ""
}
let instance1 = A.shared
instance1.aString = "A String"
let instance2 = A.shared
instance2.aString = "Another String"
print(instance1.aString, instance2.aString) //Both print "Another String"
Could some kind soul try to clear things up for me?
The static keyword in Swift does not mean the property is immutable/constant (unlike in C-based languages). static means the property is a type property, not an instance property, meaning that it is a property of the type itself, shared between all instances and not a property of each instance. For more information, read the Type Properties section of the Swift language guide.
Constants/immutable properties are declared by let, while mutable ones by var.
You can set and get static vars by using the type name (A in your case).
A.staticString = "new"
A.staticString // "new"
If you create instances of the type, you can use type(of:) to get the meta-type (A), which you can use to access static properties
let a = A()
type(of: a).staticString // "new"
let anotherA = A()
type(of: anotherA).staticString // "new"

Why does Swift BooleanLiteralConvertible require a boolean literal?

I am trying to add BooleanLiteralConvertible support to my class so I can instantiate it with a boolean. The thing that's throwing me for a loop is the distinction between a boolean value and a boolean literal.
For example, after adding the protocol I attempted this:
func setSelected(value: Bool) {
var node: MyClass = value
}
But Swift complained that it cannot convert Bool to MyClass. It took me a while to realize it has to be a boolean literal. Oddly enough the following works fine:
func setSelected(value: Bool) {
var node: MyClass = value ? true : false
}
…which seems just absolutely silly to me. Is there a legitimate reason for this seemingly very bizarre requirement?
Types conforming to BooleanLiteralConvertible can be initialized with the Boolean literals true and false, e.g.
let mc : MyClass = true
This has nothing to do with initializing the type with a Boolean value:
let value : Bool = // ... some boolean value
let mc : MyClass = value // error: cannot convert value of type 'Bool' to specified type 'MyClass'
and there is – as far as I know – no way to make such an implicit
conversion work. You would have to write a custom init method
init(bool : Bool) {
// ...
}
and initialize the object as
let value : Bool = // ... some boolean value
let mc = MyClass(bool: value)
I like the question. Only the Swift team could definitively answer, but I can speculate as to why: converting a typed value into a variable of a different type without an explicit conversion or cast is very easy to confuse with a programmer error, and in many cases is something the compiler should warn about.
Example (and assume that Person is also a StringLiteralConvertible that can be initialized with a string variable as well as a literal as you pose in your question):
struct Person {
private static var idCounter = 1
var name:String
let id:Int
init(withName name:String) {
Person.idCounter += 1
self.name = name
self.id = Person.idCounter
}
}
var person = Person(withName:"Mary")
let name = "John"
person = name
The above code looks suspiciously like a mistake, where the programmer is assigning a value of the wrong type (String) to a variable of type Person. It may in fact be a mistake. Maybe the programmer only meant to change the name of the person (person.name = name) without creating a new Person with a new unique id. Or maybe the programmer intended to assign some other value to person but made a typo or code completion error. Hard to tell without either being the original programmer, or carefully studying all the context to see whether this conversion makes sense. And it gets harder the further the assignment is from the place where the variables are originally initialized Should the compiler warn here that a value of type String is being assigned to a variable of type Person?
The example would be far more clear, and more in line with Swift conventions as:
var person = Person(withName:"Mary")
let name = "John"
person = Person(withName:name)
The above version is completely unambiguous, both to the compiler and to any other programmers who read this later.

Swift: Casting collections, and creating custom convertible protocols

Consider this Person class, which simply implements StringLiteralConvertible and assigns the string literal to name:
class Person : StringLiteralConvertible {
var name : String?
typealias StringLiteralType = String
required init(stringLiteral value: StringLiteralType) {
println("stringLiteral \(value)")
name = value
}
typealias ExtendedGraphemeClusterLiteralType = String
required init(extendedGraphemeClusterLiteral value: ExtendedGraphemeClusterLiteralType) {
println("extendedGraphemeClusterLiteral \(value)")
name = value
}
typealias UnicodeScalarLiteralType = Character
required init(unicodeScalarLiteral value: UnicodeScalarLiteralType) {
println("unicodeScalarLiteral \(value)")
name = "\(value)"
}
}
This allows me to create a Person instance using a string:
let aaron : Person = "Aaron"
I can even cast an array of Persons from an array of strings:
let names = ["John", "Jane"] as [Person]
However this only works with string literals. If I use a string variable, it fails:
let aaronString = "Aaron"
let aaron : Person = aaronString
// Error: 'NSString' is not a subtype of 'Person'
Similarly, trying to cast an array of non-literal strings fails:
let nameStrings = ["John", "Jane"]
let people : [Person] = nameStrings
// Error: 'String' is not identical to 'Person'
I have three questions:
Is there another protocol I can implement to cast a non-literal string to a Person? I'd like to do this so I can cast entire collections to convert the objects.
If no to #1, is map + an initializer the best way to perform the conversion myself?
let nameStrings = ["John", "Jane"]
let people = nameStrings.map{Person(name: $0)}
If yes to #1, is there a similar approach I can use to specify an approach to convert two objects which are unrelated in hierarchy? That is, can I work around this error without an initializer?
let rikerPerson : Person = "Riker"
let rikerEmployee = rikerPerson as Employee
// Error: 'Person' is not convertible to 'Employee'
What you are describing as “casting” isn’t really casting (in the way that, say, s = “fred”; ns = s as NSString is, or that casts in C++ are).
let names = ["John", "Jane"] as [Person]
is just another a way of writing:
let names: [Person] = ["John", "Jane"]
that is, a way of telling Swift which of the many possible versions of StringLiteralConvertible to use (and not the one for String, which is the default).
Put it another way – your as is fulfilling a similar function to the as in this snippet that disambiguates two overloaded functions that differ only by return type:
func f() -> String { return "foo" }
func f() -> Int { return 42 }
let i = f() as Int // i will be 42
let s = f() as String // s will be “foo"
No “conversion” is going on here – the as is just being used to disambiguate which f Swift calls. It’s the same with which init(stringLiteral:) is chosen.
Definitely (but only if you put a space between map and the { } ;-).
If you’re concerned about the waste of converting it all to an array just to do some other thing with it, check out lazy(a).map
Nope. In the betas, there used to be a __conversion() -> T method you could implement to do “casts” like this on your own classes – or more importantly, allowed you to pass your Person class into a function that took an Employee argument and have it be converted implicitly. But that got disappeared. Generally that kind of implicit conversion is antithetical to Swift’s style, except in rare cases (Obj-C and C interop, and implicit wrapping in optionals, being the main ones). You have to write an init for Employee that takes a Person (or some class or protocol that Person conforms to), and then call it.

F# Class with Generics : 'constructor deprecated' error

I am trying to create a a class that will store a time series of data - organized by groups, but I had some compile errors so I stripped down to the basics (just a simple instantiation) and still can't overcome the compile error. I was hoping some one may have seen this issue before. Clas is defined as:
type TimeSeriesQueue<'V, 'K when 'K: comparison> = class
val private m_daysInCache: int
val private m_cache: Map<'K, 'V list ref > ref;
val private m_getKey: ('V -> 'K) ;
private new(getKey) = {
m_cache = ref Map.empty
m_daysInCache = 7 ;
m_getKey = getKey ;
}
end
So that looks OK to me (it may not be, but doesnt have any errors or warnings) - the instantiation gets the error:
type tempRec = {
someKey: string ;
someVal1: int ;
someVal2: int ;
}
let keyFunc r:tempRec = r.someKey
// error occurs on the following line
let q = new TimeSeriesQueue<tempRec, string> keyFunc
This construct is deprecated: The use
of the type syntax 'int C' and 'C
' is not permitted here. Consider
adjusting this type to be written in
the form 'C'
NOTE This may be simple stupidity - I am just getting back from holiday and my brain is still on time zone lag...
The compiler is just saying that you need to enclose parameters of the constructor in parentheses:
// the following should work fine
let q = new TimeSeriesQueue<tempRec, string>(keyFunc)
There are some other issues though - the constructor needs to be public (otherwise you cannot call it) and the parameter of keyFunc should be also in parentheses (otherwise, the compiler will think that the type annotation is for the result of the function):
let keyFunc (r:tempRec) = r.someKey
You may also consider using implicit constructor syntax which makes class declarations a lot simpler in F#. Parameters of the constructor automatically become available in the body of the class and you can declare (private) fields simply using let:
type TimeSeriesQueue<'V, 'K when 'K: comparison>(getKey : 'V -> 'K) =
let daysInCache = 7
let cache = ref Map.empty
member x.Foo() = ()