How to use EF Include method(to load related data) in F#? - entity-framework

How to eager load related data in F# using Include method I tried this one:
_ctx.Reports.Include(x => x.Category)
and getting the following error:
Severity Code Description Project File Line Suppression State
Error FS0041 A unique overload for method 'Include' could not be determined based on type information prior to this program point. A type annotation may be needed.
Known type of argument: ^_arg3
Candidates:
- (extension) Linq.IQueryable.Include<'TEntity when 'TEntity : not struct>(navigationPropertyPath: string) : Linq.IQueryable<'TEntity>
- (extension) Linq.IQueryable.Include<'TEntity,'TProperty when 'TEntity : not struct>(navigationPropertyPath: Linq.Expressions.Expression>) : Query.IIncludableQueryable<'TEntity,'TProperty> SharpNews.Application E:\0DevelopingLearn\BackEnd\ASP.NET Core\SharpNews\SharpNews.Application\Admin\Report\GetReports.fs 44 Active
and also two errors are saying x is undefined
Am I using an incorrect syntax?

Casting to seq or IEnumerable<_> will do the trick
context.Users
.Include(fun u -> u.Roles :> seq<Role>)
open System.Collections.Generic
context.Users
.Include(fun u -> u.Roles :> IEnumerable<Role>)
.ThenInclude(fun r -> r.Permissions)

Related

EF Core 3 GroupBy multiple columns Count Throws with extensions but linq works

Here is the one that throws full exception:
var duplicateCountOriginal = _db.TableName
.GroupBy(g => new {g.ColumnA, g.ColumnB, g.ColumnC})
.Count(g => g.Count() > 1);
Exception:
System.ArgumentException: Expression of type 'System.Func2[System.Linq.IGrouping2[Microsoft.EntityFrameworkCore.Storage.ValueBuffer,Microsoft.EntityFrameworkCore.Storage.ValueBuffer],Microsoft.EntityFrameworkCore.Storage.ValueBuffer]' cannot be used for parameter of type 'System.Func2[Microsoft.EntityFrameworkCore.Storage.ValueBuffer,Microsoft.EntityFrameworkCore.Storage.ValueBuffer]' of method 'System.Collections.Generic.IEnumerable1[Microsoft.EntityFrameworkCore.Storage.ValueBuffer] Select[ValueBuffer,ValueBuffer](System.Collections.Generic.IEnumerable1[Microsoft.EntityFrameworkCore.Storage.ValueBuffer], System.Func2[Microsoft.EntityFrameworkCore.Storage.ValueBuffer,Microsoft.EntityFrameworkCore.Storage.ValueBuffer])' (Parameter 'arg1')
But the same thing works when it is written as linq (I prefer extensions)
var duplicateCount =
from a in _db.TableName
group a by new {a.ColumnA, a.ColumnB, a.ColumnC}
into g
where g.Count() > 1
select g.Key;
duplicateCount.Count()
I am unable to understand why one works or the other doesn't.
Also if I change the first one a little bit based on EF Core 3 changes like the following
var duplicateCountOriginal = _db.TableName
.GroupBy(g => new {g.ColumnA, g.ColumnB, g.ColumnC})
.AsEnumerable()
.Count(g => g.Count() > 1);
I get the following exception:
System.InvalidOperationException: Client projection contains reference to constant expression of 'Microsoft.EntityFrameworkCore.Metadata.IPropertyBase' which is being passed as argument to method 'TryReadValue'. This could potentially cause memory leak. Consider assigning this constant to local variable and using the variable in the query instead. See https://go.microsoft.com/fwlink/?linkid=2103067 for more information.
According to me, the link given by ms has no meaning to the whatever problem here is.
Please LMK if there is any logical explanation.
There is no logical explanation. Just EF Core query translation is still far from perfect and have many defects/bugs/unhandled cases.
In this particular the problem is not the query syntax or method syntax (what you call extensions), but the lack of Select after GroupBy. If you rewrite the method syntax query similar to the one using query syntax, i.e. add .Where, .Select and then Count:
var duplicateCount = _db.TableName
.GroupBy(g => new {g.ColumnA, g.ColumnB, g.ColumnC})
.Where(g => g.Count() > 1)
.Select(g => g.Key)
.Count();
then it will be translated and executed successfully.

Unknown error on VDM++ toolbox lite

I'm doing VDM++ on VDM++ toolbox lite and below is my example code:
class Course
types
public study :: numsubj : nat1
sem : nat1;
public subjpersem = nat1;
operations
public getsubj:nat1 * nat1 ==>study
getsubj(numsubj,sem) == (
subjpersem := numsubj/sem;
);
end Course
I tried to run the code. Succeeded creating the object but when I run print getsubj(10,2), it returns error Run-Time Error 120: Unknown state component
Can somebody help me thank you in advance
In Overture/VDMJ, this spec gives two type checking errors. Do these not appear in VDMTools?
Error 3247: Symbol 'subjpersem' is not an updatable variable in 'Course' (test.vpp) at line 9:5
Error 3027: Operation returns unexpected type in 'Course' (test.vpp) at line 7:8
Actual: ()
Expected: study
Type checked 1 class in 0.119 secs. Found 2 type errors

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

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

How can I use PredicateBuilder with repository pattern?

I am trying to use Joseph Albahari's PredicateBuilder with my applications Respository which is giving me the following error:
The best overloaded method match for 'MySite.DAL.Respositories.IMyObjRepository.SearchFor(System.Linq.Expressions.Expression<System.Func<MySite.DAL.MyObj,bool>>)' has some invalid arguments
Signiture for MySite.DAL.Respositories.IMyObjRepository.SearchFor:
public IQueryable<MyObj> SearchFor(Expression<Func<MyObj, Boolean>> predicate)
Code calling SearchFor:
var predicate = PredicateBuilder.True<MySite.DAL.MyObj>();
predicate = predicate.And(a => a.county.name == CountyName);
return _myObjRespository.SearchFor(predicate);
I am aware that I do not need PredicateBuilder for this query - I have simplified it for the purposes of this question. The simplified version still gives the same error.
Any help/ideas/advice appreciated.
Thank you.
I have just discovered the type expected in _myObjRespository.SearchFor() did not match the type I was setting/sending in var predicate = PredicateBuilder.True();
MyObj was replacing my object names for security/confidentiality reasons - I accidently replaced the different types on my original post.

SQL Query returning type unit while using F#

I am trying F# for the first time. I know I need to be able to access the database to do any significant work. We have been using Entity framework for some time. So I was able to use an existing Model file. The file was made using EF5 and I also installed EF5 on the F# project (using nuget). Here is the code I've written.
open System.Data
open System.Data.Entity
open Microsoft.FSharp.Data.TypeProviders
let connectionString = "metadata=res://*/Models.Model.csdl|res://*/Models.Model.ssdl|res://*/Models.Model.msl;provider=Oracle.DataAccess.Client;provider connection string='data source="(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.1.1)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=dev)))";password=888888888888888;user id=444444444444444'"
type internal edmx = EdmxFile<"Model.edmx", ResolutionFolder = #"C:\Users\ahernandez\Documents\Source Control\Web\Applications\NACS_API\NAWS_API\Models">
let internal context = new edmx.Model.Entities(connectionString)
[<EntryPoint>]
let main =
query { for ua_event in context.MV_COURSE_SCHEDULE do
select ua_event }
|> Seq.iter (fun ua_event -> printfn "%s" ua_event.EVE_EVENT_CODE)
I just get one error:
Error 1 Type mismatch. Expecting a
System.Linq.IQueryable<string> -> string [] -> int
but given a
System.Linq.IQueryable<string> -> unit
The type 'string [] -> int' does not match the type 'unit' c:\users\ahernandez\documents\visual studio 2013\Projects\TestFsOracle1\Program.fs 26 8 TestFsOracle1
The error gives me the impression that the query is failing for some reason. I would think if there was an Entity Framework error, I would see that error as well. Any ideas?