Is it possible to implement the IDbSet<T> interface in F#? - entity-framework

I am attempting to make a mock implementation of IDbSet<T>, and I happen to be doing it in F#.
type MockDbSet<'T when 'T : not struct>(items:seq<'T>) =
let collection = ResizeArray(items)
new () = MockDbSet(Seq.empty)
interface IDbSet<'T> with
member x.Add entity = collection.Add entity; entity
member x.Attach entity = collection.Add entity; entity
member x.Remove entity = collection.Remove entity |> ignore; entity
member x.Create() = Unchecked.defaultof<'T>
member x.Create<'TD when 'TD : not struct and 'TD :> 'T>() = Unchecked.defaultof<'TD>
member x.Find([<ParamArray>] values) = raise <| NotImplementedException()
member x.Local = Collections.ObjectModel.ObservableCollection(collection)
interface System.Collections.Generic.IEnumerable<'T> with
member x.GetEnumerator() =
collection.GetEnumerator() :> System.Collections.Generic.IEnumerator<_>
interface System.Collections.IEnumerable with
member x.GetEnumerator() =
collection.GetEnumerator() :> System.Collections.IEnumerator
interface IQueryable<'T> with
member x.ElementType = typeof<'T>
member x.Expression =
collection.AsQueryable().Expression
member x.Provider =
collection.AsQueryable().Provider
Everything is fine, except for this line:
member x.Create<'TD when 'TD : not struct and 'TD :> 'T>() = Unchecked.defaultof<'TD>
...which gives me these compiler errors:
error FS0698: Invalid constraint: the type used for the constraint is
sealed, which means the constraint could only be satisfied by at most
one solution
warning FS0064: This construct causes code to be less
generic than indicated by the type annotations. The type variable 'TD
has been constrained to be type ''T'.
error FS0663: This type
parameter has been used in a way that constrains it to always be ''T
when 'T : not struct'
error FS0661: One or more of the explicit class
or function type variables for this binding could not be generalized,
because they were constrained to other types
This line is attempting to implement this method, which according to that page has the following signature in C#:
TDerivedEntity Create<TDerivedEntity>()
where TDerivedEntity : class, TEntity
And this signature in F#:
abstract Create : unit -> 'TDerivedEntity when 'TDerivedEntity : not struct and 'TEntity
When I try to use the example F# signature, I get a variety of syntax errors, which doesn't surprise me because that signature doesn't even look like valid F#.
I'm not really sure what to make of these error messages, or how to write my constraints to satisfy both the interface and the F# compiler. I'm starting to wonder if it's even possible to implement this particular Microsoft interface in this particular Microsoft programming language. Any suggestions would be welcomed.

The method Create needs a subtype constraint between 2 generic type parameters. I'm afraid there is no way to add a subtype constraint to a generic type parameter based on another one in F#. They're always assumed to be equal, see the spec New constraints of the form type :> 'b are solved again as type = 'b.
See this related answer to a similar problem.
We should request to include this feature in the next F# version.

I was very disappointed by this at first. I still am in some ways, but there is a workaround in EF6. You can inherit DbSet<'TEntity> directly, and use overrides to implement the collection in memory. This will suffice for most cases; you can inherit from this type if you want a concrete implementation of Find.
type FakeDbSet<'TEntity when 'TEntity : not struct>(items: seq<'TEntity>) =
inherit DbSet<'TEntity>()
let data = ObservableCollection<'TEntity>(items)
let query = data.AsQueryable()
new() = FakeDbSet(Seq.empty)
override __.Add(item: 'TEntity) = data.Add(item); item
override __.Remove(item: 'TEntity) = data.Remove(item) |> ignore; item
override __.Attach(item: 'TEntity) = data.Add(item); item
override __.Create() = Activator.CreateInstance<'TEntity>()
override __.Local with get() = data
interface System.Collections.Generic.IEnumerable<'TEntity> with
member __.GetEnumerator() = data.GetEnumerator() :> System.Collections.Generic.IEnumerator<_>
interface System.Collections.IEnumerable with
member __.GetEnumerator() = data.GetEnumerator() :> System.Collections.IEnumerator
interface IQueryable<'TEntity> with
member __.ElementType = typeof<'TEntity>
member __.Expression = query.Expression
member __.Provider = query.Provider

Related

Why Class.java don't provide methods like `Type getType()` and `Type getGenericType()`?

Why I have to define a subclass to get the Type of superclass' generic param? Is the limit necessary?
I read the code of Fastjson of Alibaba and tried to figure out why use TypeReference must create an anonymous subclass. Then I found that an object cannot get its own generic param Type even its own Type.
public class TypeReference {
static ConcurrentMap<Type, Type> classTypeCache
= new ConcurrentHashMap<Type, Type>(16, 0.75f, 1);
protected final Type type;
protected TypeReference() {
Type superClass = getClass().getGenericSuperclass();
Type type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
Type cachedType = classTypeCache.get(type);
if (cachedType == null) {
classTypeCache.putIfAbsent(type, type);
cachedType = classTypeCache.get(type);
}
this.type = cachedType;
}
// ...
}
Sorry for my poor English. Thanks for your answers.
Because of Type Erasure.
Consider the following example
List<String> stringList = new ArrayList<>();
List<Number> numberList = new ArrayList<>();
System.out.println(stringList.getClass() == numberList.getClass());
This will print true. Regardless of the generic type, both instances of ArrayList have the same class and a single Class object. So how could this single Class object return the right Type for both objects?
We can even get a step further,
List<String> stringList = Collections.emptyList();
List<Number> numberList = Collections.emptyList();
System.out.println(stringList == (Object)numberList);
Objects do not know their generic type. If a collection is immutable and always empty, it can be used to represent arbitrary empty lists. The same applies to stateless functions
Function<String, String> stringFunction = Function.identity();
Function<Number, Number> numberFunction = Function.identity();
System.out.println(stringFunction == (Object)numberFunction);
Prints true (on most systems; this is not a guaranteed behavior).
Generic types are only retained in some specific cases, like the signatures of field and method declarations and generic super types.
That’s why you need to create a subclass to exploit the fact that it will store the declared generic supertype. While it sometimes would be useful to construct a Type instance in a simpler way and a suitable factory method can be regarded a missing feature, getting the actual generic type of an arbitrary object (or its Class) is not possible in general.

Using Class<T> as a Map key in Haxe

I'd like to store instances of models in a common provider using their classes or interfaces as a keys and then pop them up by class references. I have written some code:
class Provider {
public function new() { }
public function set<T:Any>(instance:T, ?type:Class<T>) {
if (type == null)
type = Type.getClass(instance);
if (type != null && instance != null)
map.set(type, instance);
}
public function get<T:Any>(type:Class<T>):Null<T> {
return cast map.get(type);
}
var map = new Map<Class<Any>, Any>();
}
...alas, it's even doesn't compile.
Probably I have to use qualified class name as a key rather than class/interface reference? But I'd like to keep neat get function design that takes type as argument and returns object just of type taken, without additional type casting.
Is it possible or should I change my approach to this problem?
The issue of using Class<T> as a Map key come up every so often, here is a related discussion. The naive approach of Map<Class<T>, T> fails to compile with something like this:
Abstract haxe.ds.Map has no #:to function that accepts haxe.IMap<Class<Main.T>, Main.T>`
There's several different approaches to this problem:
One can use Type reflection to obtain the fully qualified name of a class instance, and then use that as a key in a Map<String, T>:
var map = new Map<String, Any>();
var name = Type.getClassName(Main);
map[name] = value;
For convenience, you would probably want to have a wrapper that does this for you, such as this ClassMap implementation.
A simpler solution is to simply "trick" Haxe into compiling it by using an empty structure type ({}) as the key type. This causes ObjectMap to be chosen as the underlying map implementation.
var map = new Map<{}, Any>();
map[Main] = value;
However, that allows you to use things as keys that are not of type Class<T>, such as:
map[{foo: "bar"}] = value;
The type safety issues of the previous approach can be remedied by using this ClassKey abstract:
#:coreType abstract ClassKey from Class<Dynamic> to {} {}
This still uses ObjectMap as the underlying map implementation due to the to {} implicit cast. However, using a structure as a key now fails at compile time:
var map = new Map<ClassKey, Any>();
map[{foo: "bar"}] = value; // No #:arrayAccess function accepts arguments [...]

Allowing nulls on a record type F#

I'm trying to make a type extension for MongoDB C# Driver that will return an option type instead of null when trying to execute a query that yields 0 results.
I've run into a few issues on the way, but right now there is just one thing in the way.
Here is the code
[<Extension>]
type Utils () =
[<Extension>]
static member inline tryFindOne(x: MongoCollection<'T>, query) =
match x.FindOne(query) with
| null -> None
| value -> Some value
[<CLIMutable>]
type Entity =
{ Id : ObjectId; Name : string }
static member Create(name) =
{ Id = ObjectId(); Name = name }
The problem of course is that the record type Entity to the F# compiler does not conform to the type constraint of the extension method('T : null) but I have to have the contraint to be able to pattern match against nulls. Of course it's sort of a nonsensical thing because the type Entity is very much "nullable" for interop purposes and will be returned as null whenever you try to query a MongoDB collection which yields 0 results. I tried to set the attribute [<AllowNullLiteral>] but unfortunately it only works with classes. So alas I'm stuck, I could make Entity into a class instead but I think records are more idiomatic F#.
I think the following should work:
[<Extension>]
type Utils () =
[<Extension>]
static member inline tryFindOne(x: MongoCollection<'T>, query) =
let theOne = x.FindOne(query);
if (box theOne = null) None else Some(theOne)
I have borrowed the idea from Sergey Tihon's post here:
https://sergeytihon.wordpress.com/2013/04/10/f-null-trick/
Alternative way to do the null check without boxing:
[<Extension>]
type Utils () =
[<Extension>]
static member inline tryFindOne(x: MongoCollection<Entity>, query) =
let theOne = x.FindOne(query)
if obj.ReferenceEquals(theOne, null) then None else Some(theOne)

Records satisfying implicit interface w/o re-implementing

Seeing a record already has a public Getter/(Setter) for its fields, is it possible to specify that a record satisfies a matching interface without re-implementing it?
For example:
type IText =
abstract text : string with get,set
type TextRec =
{
mutable text : string
}
Now seeing the Record already implements this interface implicitly, I'd like to put an "inherit IText" or "interface IText" (with no body) on the record, but it appears I can't do that. As it is, I believe I have to re-implement the interface by adding this to the record:
interface IText with
member this.text
with get() = this.text
and set(v) = this.text <- v
thanks
F# currently does not support implicit interface implementations (not even for classes), but it is one of the frequently requested features, so it might happen in the future. I certainly see why this would be useful.
I don't think there is any good workaround for this - the best option is probably to write the additional piece of code needed to implement the interface.
If you wanted to be adventurous, you could try writing a "wrapping" function that creates an interface implementation from a value that provides the required members. Using static member constraints, you can require the members to be there (without actually implementing the interface):
type IText =
abstract Text : string with get, set
let inline wrap (a:^T) =
{ new IText with
member x.Text
with get() = (^T : (member Text : string) (a))
and set(v) = (^T : (member set_Text : string -> unit) (a, v)) }
Static member constraints (used in the implementation of wrap) are mainly useful for generic numerical computations, so this is a bit of a stretch (and certainly an advanced F# feature), but it does the trick:
type Rect = { mutable Text : string }
let i = wrap { Text = "Hi" }
i.Text <- i.Text + " there!"

Need help understanding Generics, How To Abstract Types Question

I could use some really good links that explain Generics and how to use them. But I also have a very specific question, relater to working on a current project.
Given this class constructor:
public class SecuredDomainViewModel<TDomainContext, TEntity> : DomainViewModel<TDomainContext, TEntity>
where TDomainContext : DomainContext, new()
where TEntity : Entity, new()
public SecuredDomainViewModel(TDomainContext domainContext, ProtectedItem protectedItem)
: base(domainContext)
{
this.protectedItem = protectedItem;
}
And its creation this way:
DomainViewModel d;
d = new SecuredDomainViewModel<MyContext, MyEntityType>(this.context, selectedProtectedItem);
Assuming I have 20 different EntityTypes within MyContext, is there any easier way to call the constructor without a large switch statement?
Also, since d is DomainViewModel and I later need to access methods from SecuredDomainViewModel, it seems I need to do this:
if (((SecuredDomainViewModel<MyContext, MyEntityType>)d).CanEditEntity)
But again "MyEntityType" could actually be one of 20 diffent types. Is there anyway to write these types of statements where MyEntityType is returned from some sort of Reflection?
Additional Info for Clarification:
I will investigate ConstructorInfo, but I think I may have incorrectly described what I'm looking to do.
Assume I have the DomainViewModel, d in my original posting.
This may have been constructed via three possible ways:
d = new SecuredDomainViewModel<MyContext, Order>(this.context, selectedProtectedItem);
d = new SecuredDomainViewModel<MyContext, Invoice>(this.context, selectedProtectedItem);
d = new SecuredDomainViewModel<MyContext, Consumer>(this.context, selectedProtectedItem);
Later, I need to access methods on the SecuredDomainViewModel, which currently must be called this way:
ex: if (((SecuredDomainViewModel<MyContext, Order)d).CanEditEntity)
ex: if (((SecuredDomainViewModel<MyContext, Invoice)d).CanEditEntity)
ex: if (((SecuredDomainViewModel<MyContext, Consumer)d).CanEditEntity)
Assuming I have N+ entity types in this context, what I was hoping to be able to do is
something like this with one call:
ex: if (((SecuredDomainViewModel<MyContext, CurrentEntityType)d).CanEditEntity)
Where CurrentEntityType was some sort of function or other type of call that returned Order, Invoice or Consumer based on the current item entity type.
Is that possible?
You can create a non-generic interface that has the CanEditEntity property on it, make SecuredDomainViewModel inherit off that, then call the property through the interface...
Also, the new() constructor allows you to call a constructor on a generic type that has no arguments (so you can just write new TEntity()), but if you want to call a constructor that has parameters one handy trick I use is to pass it in as a delegate:
public void Method<T>(Func<string, bool, T> ctor) {
// ...
T newobj = ctor("foo", true);
// ...
}
//called later...
Method((s, b) => new MyClass(s, b));
I can't help on the links, and likely not on the type either.
Constructor
If you have the Type, you can get the constructor:
ConstructorInfo construtor = typeof(MyEntityType).GetConstructor(new object[]{TDomainContext, ProtectedItem});
Type
I'm not really sure what you're looking for, but I can only see something like
if (((SecuredDomainViewModel<MyContext, entityType>)d).CanEditEntity)
{
entityType=typeof(Orders)
}
being what you want.