I am trying to find the LINQ equaivalent of
select * from usertable where groupof=groupuser
I have the following code
var UserList = await usertableservice.GetUsers() as List<UserTable>;
var query = from c in UserList
where c.GroupOf.Contains(groupuser)
select c;
return query.FirstOrDefault().UserId;
The GetUsers() function will list all the users then I filter if the groupof column contains a specific string.
But what happens here is
select * from usertable (this may contain 1 million records)
then I am filtering, I guess its totally wrong and resource intensive. What is the best way of doing this?
service layer code:
public async Task<IEnumerable<UserTable>> GetUsers()
{
try
{
var response = await httpClient.GetAsync("api/userinfo");
if (response.IsSuccessStatusCode)
{
if (response.StatusCode == System.Net.HttpStatusCode.NoContent)
{
return Enumerable.Empty<UserTable>();
}
string s = await response.Content.ReadAsStringAsync();
//return Enumerable.Empty<LookupTable>();
return await response.Content.ReadFromJsonAsync<IEnumerable<UserTable>>();
}
else
{
var message = await response.Content.ReadAsStringAsync();
throw new Exception($"Http status code: {response.StatusCode} message: {message}");
}
}
catch (Exception ex)
{
//Log exception
throw;
}
}
controller code
[HttpGet]
public async Task<ActionResult<IEnumerable<UserTable>>> GetAllUsers()
{
try
{
var list = await this.userTableRepository.GetUsers();
if (list == null)
{
return NotFound();
}
else
{
//var LookuplistDtos = lookuplist.ConvertToDto();
return Ok(list);
}
}
catch (Exception)
{
return StatusCode(StatusCodes.Status500InternalServerError,
"Error retrieving data from the database");
}
}
Repository code
public async Task<IEnumerable<UserTable>> GetUsers()
{
var item = await this.riskDBContext.UserTables
.ToListAsync();
return item;
}
The flow is
UI -> service layer -> api -> repository
I agree - it would be wrong to pass million items through api layer for filtering in UI layer.
IQueryable can't be used in UI layer because it can't be serialized - so it cannot be moved through Api layer.
All heavy data filtering should be in repository level but filtering parameter "groupuser" should be passed through flow from UI to repository.
For the sake of brevity and clarity, I did not include error handling here.
UI code:
var User = await usertableservice.GetUserByGroup(groupuser);
return User.UserId;
Service layer code:
public async Task<UserTable> GetUserByGroup(string userGroup)
{
var response = await httpClient.GetAsync("api/userbygruop?userGroup="+userGroup);
return await response.Content.ReadFromJsonAsync<UserTable>();
}
Api Controller code:
[HttpGet]
[Route("userbygruop")]
public async Task<ActionResult<UserTable>> GetUserByGroup(string userGroup)
{
var user = await this.userTableRepository.GetUserByGroup(userGroup);
return Ok(user);
}
Repository code:
public async Task<UserTable> GetUserByGroup(string userGroup)
{
var UsersQuery = this.riskDBContext.UserTables;
var query = from c in UsersQuery
where c.GroupOf.Contains(userGroup)
select c;
var filteredUser = await query.FirstOrDefaultAsync();
return filteredUser;
}
Related
I am using EF Core 5.0.
I have a class called JobApplicationManager that OwnsMany() of JobApplications.
modelBuilder.Entity<JobApplicationManager>().OwnsMany(s => s.JobApplicationCategories, a =>
{
a.Property<DateTime>("CreatedDate");
a.Property<DateTime>("UpdatedDate");
a.ToTable("JobApplicationManagerCategories");
});
modelBuilder.Entity<JobApplication>().OwnsMany(s => s.JobApplicationCategories, a =>
{
a.Property<DateTime>("CreatedDate");
a.Property<DateTime>("UpdatedDate");
a.ToTable("JobApplicationCategories");
});
Current state: There is one JobApplicationManager in the DB with one JobApplication.
Action: I add another JobApplication to the JobApplicationManager.
In my DBContext.SaveChangesAsync() I call ChangeTracker.Entries() and the following is the entities:
As you can see the first entry is the JobApplication with status of Added.
Also in this DBContect you can see the JobApplicationManager has two JobApplications:
The next step I can ChangeTracker.HasChanges() which returns false so therefor base.SaveChangesAsync() returns 0 number of entities written.
I dont know what to do.
Here is the code that creates my entity and calls my repository:
var mgr = await AMRepository.GetJobApplicationManagerAsync(command.JobApplicationManagerID);
var newJobApplication = mgr.AddJobApplication(command.JobDescriptionURL, command.JobTitle, command.FileName, command.CompanyName, command.GeographicLocation, command.RecruiterName, command.JobApplicationCategories);
// Update the Repository
AMRepository.Update(mgr);
commandResult = await AMRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken);
Here is the code in my Repository:
public void Update(JobApplicationManager applicationManager)
{
try
{
AppManagerContext.Entry(applicationManager).State = EntityState.Modified;
}
Here is the code in my DBContext for SaveEntitiesAsync():
public async Task<bool> SaveEntitiesAsync(CancellationToken cancellationToken = default(CancellationToken))
{
var changesFlag1 = ChangeTracker.HasChanges();
// Dont save the enumeration Value Object types
try
{
var enumerationEntries = ChangeTracker.Entries()
.Where(x => EnumerationTypes.Contains(x.Entity.GetType()));
foreach (var enumerationEntry in enumerationEntries)
{
enumerationEntry.State = EntityState.Unchanged;
}
}
catch (Exception exc)
{
Console.WriteLine(exc.ToString());
}
UpdateShadowProperties();
var numberOfStateEntitiesWritten = 0;
try
{
numberOfStateEntitiesWritten = await base.SaveChangesAsync(cancellationToken);
}
catch (DbUpdateException exc)
{
Console.WriteLine(exc.ToString());
}
if (numberOfStateEntitiesWritten == 0)
{
return false;
}
return true;
}
Here is the code from the Repository for GetJobApplicationManagersAsync():
public async Task<IEnumerable<JobApplicationManager>> GetJobApplicationManagersAsync() => await AppManagerContext.JobApplicationManagers.ToListAsync();
Within mgr.AddApplication() all I do is add POCO classes to the mgr. There is no infrastructure related activities (i.e. using DBContext)>
I appreciate this question has been asked. But I seem to have done what people are suggesting to fix it and I am still having the same issue. I can't see where I am going wrong. Any help would be greatly appreciated.
I am getting the following error:
InvalidOperationException: A second operation started on this context
before a previous operation completed. This is usually caused by
different threads using the same instance of DbContext
In these specific areas:
return await _dbContext.Set<T>().FindAsync(id);
var editPost = await _postRepository.GetByIdAsync(postModel.Id);
await _postAppService.Update(mapped);
await _postPageService.UpdatePost(Post);
Here is my code:
Just to add a bit more detail. I will list the exact steps:
First I select the post I would like to edit. The following gets called:
public async Task<IActionResult> OnGetAsync(int? postId)
{
if (postId == null)
{
return NotFound();
}
Post = await _postPageService.GetPostById(postId.Value);
if (Post == null)
{
return NotFound();
}
return Page();
}
public async Task<PostViewModel> GetPostById(int postId)
{
var post = await _postAppService.GetPostById(postId);
var mapped = _mapper.Map<PostViewModel>(post);
return mapped;
}
public async Task<PostModel> GetPostById(int postId)
{
var post = await _postRepository.GetByIdAsync(postId);
var mapped = ObjectMapper.Mapper.Map<PostModel>(post);
return mapped;
}
public virtual async Task<T> GetByIdAsync(int id)
{
return await _dbContext.Set<T>().FindAsync(id);
}
I then make my changes and click the update button:
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
try
{
await _postPageService.UpdatePost(Post);
}
catch (DbUpdateConcurrencyException)
{
if (!PostExists(Post.Id))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToPage("./Index");
}
public async Task UpdatePost(PostViewModel postViewModel)
{
var mapped = _mapper.Map<PostModel>(postViewModel);
if (mapped == null)
throw new Exception($"Entity could not be mapped.");
await _postAppService.Update(mapped);
_logger.LogInformation($"Entity successfully added - IndexPageService");
}
public async Task Update(PostModel postModel)
{
ValidatePostIfNotExist(postModel);
var editPost = await _postRepository.GetByIdAsync(postModel.Id);
if (editPost == null)
throw new ApplicationException($"Entity could not be loaded.");
ObjectMapper.Mapper.Map<PostModel, Post>(postModel, editPost);
await _postRepository.UpdateAsync(editPost);
_logger.LogInformation($"Entity successfully updated - AspnetRunAppService");
}
public async Task UpdateAsync(T entity)
{
_dbContext.Entry(entity).State = EntityState.Modified;
await _dbContext.SaveChangesAsync();
}
I have also set the lifetime of my DbContext to Transient.
services.AddDbContext<MyJourneyContext>(c => c.UseSqlServer(_config.GetConnectionString("MyJourneyConnectionString")),
ServiceLifetime.Transient);
So I am using await and have set the lifetime of my DbContext to Transient. But I am clearly still doing something wrong. Can anyone help me with this?
I am writing controllers in Web API 2, against which odata queries will be executed:
[Route("", Name = "GetAccount")]
[HttpGet]
public async Task<IHttpActionResult> GetAccount()
{
var query = Request.RequestUri.PathAndQuery.Split('/')[2]; //this query variable will be something "filter=name eq 'alex'"
var response = _accountService.Get(query);
if (!response.Result.IsSuccessStatusCode)
{
return NotFound();
}
var readAsAsync = response.Result.Content.ReadAsAsync<object>();
if (readAsAsync == null)
{
return NotFound();
}
var result = await readAsAsync;
return Ok(result);
}
How do I inject the Request, specifically as it relates to: var query = Request.RequestUri.PathAndQuery.Split('/')[2]; ?
Here's a very basic test that I've written for this controller:
[TestMethod]
public void GetAccount_Returns_IHttpActionResultTask()
{
var accountsService = new Mock<IAccountService>();
var sut = new AccountsController(accountsService.Object);
Assert.IsInstanceOfType(sut.GetAccount(), typeof(Task<IHttpActionResult>));
}
In order to test with different values for Request.RequestUri...., how do I rewrite my controller to be more testable?
Set the Request property on the ApiCntroller.
[TestMethod]
public async Task GetAccount_Returns_IHttpActionResult() {
//Arrange
var accountsService = new Mock<IAccountService>();
var sut = new AccountsController(accountsService.Object);
sut.Request = new HttpRequestMessage {
RequestUri = new Uri("http://localhost/api/accounts?filter=name")
};
//Act
var result = await sut.GetAccount();
//Assert
Assert.IsInstanceOfType(result, typeof(IHttpActionResult));
}
Also there or some potential blocking issues with the method under test. Mixing async/await with .Result blocking calls can cause deadlocks.
Refactor:
[Route("", Name = "GetAccount")]
[HttpGet]
public async Task<IHttpActionResult> GetAccount() {
var query = Request.RequestUri.PathAndQuery.Split('/')[2]; //this query variable will be something "filter=name eq 'alex'"
var response = await _accountService.Get(query);
if (!response.IsSuccessStatusCode) {
return NotFound();
}
var readAsAsync = response.Content.ReadAsAsync<object>();
if (readAsAsync == null) {
return NotFound();
}
var result = await readAsAsync;
return Ok(result);
}
I have a web api which I'm calling (this is working correctly)
I call this like so
public ActionResult Index()
{
var mod = Checksomething();
return View();
}
public async Task Checksomething()
{
try
{
var client = new HttpClient();
var content = new StringContent(JsonConvert.SerializeObject(new UserLogin { EmailAddress = "SomeEmail#Hotmail.com", Password = "bahblah" }));
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var response = await client.PostAsync("http://localhost:28247/api/UserLoginApi2/CheckCredentials", content);
var value = await response.Content.ReadAsStringAsync();
// I need to return UserProfile
var data = JsonConvert.DeserializeObject<UserProfile[]>(value);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
My web api passes back a model called UserProfile, I'm having great difficulty trying to return data back to the Index controller, would someone please enlighten me.
You need to change your method signature to use the generic version of Task
public async Task<ActionResult> Index()
{
UserProfile[] profiles = await Checksomething();
if (profiles.Any())
{
var user = profiles.First();
string username = user.FirstName;
// do something w/ username
}
return View();
}
public async Task<UserProfile[]> Checksomething()
{
try
{
var client = new HttpClient();
var content = new StringContent(JsonConvert.SerializeObject(new UserLogin { EmailAddress = "SomeEmail#Hotmail.com", Password = "bahblah" }));
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var response = await client.PostAsync("http://localhost:28247/api/UserLoginApi2/CheckCredentials", content);
var value = await response.Content.ReadAsStringAsync();
// I need to return UserProfile
return JsonConvert.DeserializeObject<UserProfile[]>(value);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
The returned Task will be unwrapped and your caller will be given the Result of the Task, which in this case will be UserProfile[]
I'm having a problem with an async method that I implemented. The method basically makes a HttpRequest to a resource and deserializes the string if the request is successful. I wrote a test for the method, and it works. But the method does never return when I call it from a controller?
public async Task<IEnumerable<T>> Get()
{
try
{
var resourceSegmentUri = new Uri(_uri, UriKind.Relative);
var response = await _client.GetAsync(resourceSegmentUri);
if (response.IsSuccessStatusCode)
{
var submission = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<IEnumerable<T>>(submission);
}
if (response.Content != null)
{
var message = response.Content.ReadAsStringAsync();
throw new WebException(message.Result, (WebExceptionStatus)response.StatusCode);
}
}
catch (WebException e)
{
Logger.Error("GET Request failed with status: {0}", e.Status);
throw;
}
throw new Exception();
}
Code that never returns:
public ActionResult Index()
{
var api = new Api();
var test = api.Get().Result; //Never returns
return View();
}
Test that works:
[Test]
public void GetShouldReturnIfSuccessfulRequest()
{
var api = new Api();
var submission = api.Get();
Console.WriteLine(JsonConvert.SerializeObject(submission));
Assert.NotNull(submission);
}
Does anyone know the problem?
You've got a deadlock because you're calling .Result in your controller action.
If you use async/await then you have to use asynchronous actions too.
So something like this should fix it:
public async Task<ActionResult> Index()
{
var api = new Api();
var test = await api.Get(); // Should return
}
There's a comprehensive article about this here: Using Asynchronous Methods in ASP.NET MVC 4