I'm pretty new to dotnet asp core and would like to use async methods to talk with the database to follow good practices.
In a scenario I'm facing I need to retrieve First record of a table that matches a condition. It could or could not exist. So, I use the method using Entity Framework dbContext.mytable.First but it seems it isn't asyncronous.
Should I get rid of it and just use dbContext.mytable.FindAsync?
You are probably missing a reference
EntityFrameworkQueryableExtensions.FirstAsync Method
note the namespace and assembly
Namespace: Microsoft.EntityFrameworkCore
Assembly: Microsoft.EntityFrameworkCore.dll
That should allow the use of FirstAsync
var result = await dbContext.mytable.FirstAsync(x => x.property == something);
If there is a possibility that the record does not exist then use FirstOrDefaultAsync
var result = await dbContext.mytable.FirstOrDefaultAsync(x => x.property == something);
Related
This is the specific line of code that I need to mock.
IGenericRepository<Foo> _fooRepository;
var listOfIds = await _fooRepository.GetAllAsync(o => o.Ids);
This is getting a list of int to represent the IDs in this data table. In other words,
select Ids from Table
FooRepository is implemented with IGenericRepository all using Entity Frameworks. The Ids field in the underlying table is just integer values and I'm trying to get a list of int out of it. I don't want any other columns.
So I have tried the following to no avail:
1.
_listOfIds = new List<int> {1,2,3,4,5};
_fooRepositoryMock.Setup(o => o.GetAllAsync(
It.IsAny<Expression<Func<Foo, bool>>>()))
.Returns((Expression<Func<Foo, bool>> Predicate) =>
Task.FromResult(_listOfids.Where(Predicate.Compile()).ToList()
as ICollection<int>));
With this, IntelliSense complains that it cannot convert from...
'System.Func<Foo, Bool> to System.Func<int, int, bool>"
I tried at first messing around with the different types going in and out of the Func delegate. But I'm still stuck with the same error.
2.
I tried to then just use a default as I don't particularly mind if it tests this line completely. The list of IDs is just used later on in the method. But I need to mock it because if it's null, it's causing a test further down the test method to fail.
_listOfids= new List<int> {1,2,3,4,5};
_fooRepositoryMock.SetReturnsDefault(_listOfIds);
For some reason, when debugging the listOfIds remains null.
I'm kinda stuck on this one. The only thing that I can think of is to just stick this line of code into a helper method and mock the helper instead. But it just seems a really shoddy way to rewrite the code just to make a test pass.
You don't have to specify the parameters for Returns method call. Also Moq includes another method for setting results of async methods.
_fooRepositoryMock.Setup(o => o.GetAllAsync(It.IsAny<Expression<Func<Foo, int>>>()))
.ReturnsAsync(idList);
I am using LinqPad to test my query. This query works when the LInqPad connection is to my database (LInq to SQL) but it does not work when I change the connection to use my Entity Framework 5 Model.dll. (Linq to Entity). This is in C#.
I have two tables called Plan and PlanDetails. Relationship is one Plan to many PlanDetails.
var q = from pd in PlanDetails
select new {
pd.PlanDetailID,
ThePlanName = (from p in this.Plans
where p.PlanID == pd.PlanID
select p.PlanName)
};
var results = q.ToList();
q.Dump(); //This is a linqpad method to output the result.
I get this error "NotSupportedException: Unable to create a constant value of type 'Domain.Data.Plan'. Only primitive types or enumeration types are supported in this context." Any ideas why this only works with Linq to SQL?
basically it means you are using some complex datatype inside the query for comparison.
in your case i suspect from p in this.Plans where p.PlanID == pd.PlanID is the culprit.
And it depends on DataProvider. It might work for Sql Data Provider, but not for SqlCE data Provider and so on.
what you should do is to convert your this.Plans collection into a primitive type collection containing only the Ids i.e.
var integers = PlanDetails.Plans.Select(s=>s.Id).ToList();
and then use this list inside.
var q = from pd in PlanDetails
select new {
pd.PlanDetailID,
ThePlanName = (from p in integers
where p == pd.PlanID
select pd.PlanName)
};
I got this error when i was trying to null check for a navigational property in the entity framework expression
I resolved it by not using the not null check in the expression and just using Any() function only.
protected Expression<Func<Entities.Employee, bool>> BriefShouldAppearInSearchResults(
IQueryable<Entities.Employee> briefs, string username)
{
var trimmedUsername = NameHelper.GetFormattedName(username);
Expression<Func<Entities.Employee, bool>> filterExpression = cse =>
cse.Employee.Cars.All(c =>
c.Employee.Cars!=null && <--Removing this line resolved my issue
c.Employee.Cars.Any(cur => cur.CarMake =="Benz")));
return filterExpression;
}
Hope this helps someone!
This is a Linqpad bug if you like (or a peculiarity). I found similar behaviour myself. Like me, you may find that your query works with an ObjectContext, but not a DbContext. (And it works in Visual Studio).
I think it has to do with Linqpad's inner structure. It adds MergeAs (AppendOnly) to collections and the context is a UserQuery, which probably contains some code that causes this bug.
This is confirmed by the fact that the code does work when you create a new context instance in the Linqpad code and run the query against this instance.
If the relationship already exists.
Why not simply say.
var q = from pd in PlanDetails
select new {
pd.PlanDetailID,
ThePlanName = pd.Plan.PlanName
};
Of course i'm assuming that every PlanDetail will belong to a Plan.
Update
To get better results from LinqPad you could tell it to use your own assembly (which contains your DbContext) instead of the default Datacontext it uses.
I have this code
var list = _db.Projects.Where(item => item.Loc =="IN").Select(p => new {id=p.Id, title=p.Title,pc=p.PostalCode });
Project table having lot of columns, i need to query required columns dynamically and load from database, not all columns along with data.
Questions:
how to write lambda expressions for linq select ?
How to reduce data reads on database by selecting specific cols, entity framework ?
Look at the expression the C# compiler generated and try to replicate what it does:
Expression<Func<Project, object>> lambda =
(Project p) => (object)new {id=p.Id, title=p.Title,pc=p.PostalCode };
I hope this code compiles. If not, you'll surely be able to fix it. Afterwards, look at the contents of the lambda variable.
Note, that the cast to object is only there to make this compile. You don't need/want that is production.
when using a MVC 3 collection that uses IEnumerable, is there a way to make small queries work to find single values? I've been experimenting with little success.
I have a collection of settings that have descriptions and settings. The problem is exposing one of them, as each is unique. I've tried something like this:
var appl = _service.GetSettings(id, app); //Call to service layer & repository
appl.Select(a => a.setting_value.Where(a.setting_name.StartsWith("Login")));
With little success (unless I'm missing something). Is it possible to select one item from an enumerable collection and either pass it to a ViewBag or ViewData object? What I would like to do is something like the following:
var appl = _service.GetSettings(id, app); //Call to service layer & repository
ViewBag.Login = appl.Select(a => a.setting_value.Where(a.setting_name.StartsWith("Login")));
And pass this to the view, since I have a view that now combines a collection with single values.
The following seems to work within the view:
Application Name #Html.TextBox("application_name", #Model.FirstOrDefault().app_name)
But I'm not sure if this violates separation of concerns. Am I on the wrong path here? Thank you!
EDIT: Here is what I needed. The answers below got me very very close +1 +1
ViewBag.Login = appl.Where(a => a.setting_name.StartsWith("Login")).FirstOrDefault().setting_value
ViewBag.Login = appl.Select(a => a.setting_value.Where(a.setting_name.StartsWith("Login"))).FirstOrDefault();
This will select the first object that matches your criteria and return a single result or null
var appl = _service.GetSettings(id, app);
ViewBag.Login = appl
.Where(a => a.setting_name.StartsWith("Login"))
.FirstOrDefault();
I have two Entity Framework 4 Linq queries I wrote that make use of a custom class method, one works and one does not:
The custom method is:
public static DateTime GetLastReadToDate(string fbaUsername, Discussion discussion)
{
return (discussion.DiscussionUserReads.Where(dur => dur.User.aspnet_User.UserName == fbaUsername).FirstOrDefault() ?? new DiscussionUserRead { ReadToDate = DateTime.Now.AddYears(-99) }).ReadToDate;
}
The linq query that works calls a from after a from, the equivalent of SelectMany():
from g in oc.Users.Where(u => u.aspnet_User.UserName == fbaUsername).First().Groups
from d in g.Discussions
select new
{
UnReadPostCount = d.Posts.Where(p => p.CreatedDate > DiscussionRepository.GetLastReadToDate(fbaUsername, p.Discussion)).Count()
};
The query that does not work is more like a regular select:
from d in oc.Discussions
where d.Group.Name == "Student"
select new
{
UnReadPostCount = d.Posts.Where(p => p.CreatedDate > DiscussionRepository.GetLastReadToDate(fbaUsername, p.Discussion)).Count(),
};
The error I get is:
LINQ to Entities does not recognize the method 'System.DateTime GetLastReadToDate(System.String, Discussion)' method, and this method cannot be translated into a store expression.
My question is, why am I able to use my custom GetLastReadToDate() method in the first query and not the second? I suppose this has something to do with what gets executed on the db server and what gets executed on the client? These queries seem to use the GetLastReadToDate() method so similarly though, I'm wondering why would work for the first and not the second, and most importantly if there's a way to factor common query syntax like what's in the GetLastReadToDate() method into a separate location to be reused in several different other LINQ queries.
Please note all these queries are sharing the same object context.
I think your better of using a Model Defined Function here.
Define a scalar function in your database which returns a DateTime, pass through whatever you need, map it on your model, then use it in your LINQ query:
from g in oc.Users.Where(u => u.aspnet_User.UserName == fbaUsername).First().Groups
from d in g.Discussions
select new
{
UnReadPostCount = d.Posts.Where(p => p.CreatedDate > myFunkyModelFunction(fbaUsername, p.Discussion)).Count()
};
and most importantly if there's a way to factor common query syntax like what's in the GetLastReadToDate() method into a separate location to be reused in several different places LINQ queries.
A stored procedure would probably be one way to store that 'common query syntax"...EF, at least 4.0, works very nicely with SP's.