Why EF Core navigation properties doesnt fill? - entity-framework

I face a problem with below code
public async Task<IActionResult> Index()
{
var mainPageViewModel = new MainPageViewModel()
{
Walls = await _unitOfWork.Walls.GetAllAsync(),
PopularStoreProducts = await Context.Set<StoreProduct>().Include(sp => sp.Product).Include(sp => sp.Store).ToListAsync(),
Reviews = await _unitOfWork.Reviews.GetAllWithIncludeAsync()
};
var cartItems = await Context.Set<CartItem>().Include(ci => ci.StoreProduct).ThenInclude(sp => sp.Product)
.Include(ci => ci.StoreProduct).ThenInclude(sp => sp.Store).ToListAsync(); ;
return View(mainPageViewModel);
}
When I trace above code, cartItems.StoreProduct won't be null but an empty StoreProduct.
Everything will be fine when I remove this line:
PopularStoreProducts = await Context.Set<StoreProduct>().Include(sp => sp.Product).Include(sp => sp.Store).ToListAsync(),
My question is that why navigation properties sets empty when I already read that navigation properties in their one's queries.
Thanks in advance.

Related

How to update multiple rows of a database table in ASP.NET Core

I want to update multiple rows in ASP.NET Core, but I get an error:
InvalidOperationException: The entity type 'EntityQueryable' was not found. Ensure that the entity type has been added to the model.
This is my code:
var data = _db.UserTable.Where(a => a.CityIDn == selectedid);
foreach (var items in data)
{
await Task.Run(() =>
{
items.CityID = 2;
});
_db.Update(data);
await _db.SaveChangesAsync();
}
Try this for multiple rows:
var data = _db.UserTable.Where(a => a.CityIDn == selectedid).ToList();
foreach (var item in data)
{
item.CityID = 2;
_db.UserTable.Update(item);
}
await _db.SaveChangesAsync();
And for one record, try like this:
var data = _db.UserTable.Where(a => a.CityIDn == selectedid).FirstOrDefault();
if(data != null)
{
data.CityID = 2;
_db.UserTable.Update(data );
await _db.SaveChangesAsync();
}
The content of Update should be items, it worked for me, you can have a try.
var data = _db.UserTable.Where(a => a.CityIDn == selectedid).ToList();
foreach (var items in data)
{
await Task.Run(() =>
{
items.CityID = 2;
});
_db.Update(items);
await _db.SaveChangesAsync();
}

How to EF.Property<T> method works with included queries

I trying write a generic method for create response to datatables ajax request;
public static Response<T> CreateResponse<T>(IQueryable<T> query, Request request) where T : class
{
query = query.AsNoTracking();
var filtered = query;
if (!string.IsNullOrEmpty(request.Search.Value))
{
var keywords = Regex.Split(request.Search.Value, #"\s+").ToList();
request
.Columns
.Where(p => p.Searchable)
.ToList()
.ForEach(c =>
keywords.ForEach(k =>
{
filtered = filtered.Intersect(query.Where(p => EF.Functions.Like(EF.Property<string>(p, c.Name), $"%{k}%")));
})
);
}
var ordered = filtered;
request.Order.ForEach(p => ordered = p.Dir == "asc" ? ordered.OrderBy(q => EF.Property<T>(q, request.Columns[p.Column].Name)) : ordered.OrderByDescending(q => EF.Property<T>(q, request.Columns[p.Column].Name)));
var paged = ordered.Skip(request.Start).Take(request.Length);
return new Response<T> { draw = request.Draw, recordsTotal = query.Count(), recordsFiltered = filtered.Count(), data = paged.ToList() };
}
My problem is, when query parameter is IIncludableQueryable EF.Property method can't locate sub properties. For example;
DataTables.CreateResponse<Rayon>(context.Rayons.Include(p=>p.User), parameters);
EF.Property<T>.Property<string>(p, "Name") is working but, EF.Property<T>.Property<string>(p, "User.Name") is not working, exception message is "EF.Property called with wrong property name."
Sorry for bad English.

Moq MongoDB UpdateOneAsync method for unit testing

I want to moq update method that is using mongodbContext. here is what i am trying to do but its not working. how to pass UpdateResult return type .ReturnsAsync<UpdateResult>(). I am very new to Mongodb database Unit Testing with .net core.
public void UpdateEventAsync_Test()
{
//Arrange
var eventRepository = EventRepository();
var pEvent = new PlanEvent
{
ID = "testEvent",
WorkOrderID = "WorkOrderID",
IsDeleted = false,
IsActive = true,
EquipmentID = "EquipmentID"
};
////Act
mockEventContext.Setup(s => s.PlanEvent.UpdateOneAsync(It.IsAny<FilterDefinition<PlanEvent>>(), It.IsAny<UpdateDefinition<Model.EventDataModel.PlanEvent>>(), It.IsAny<UpdateOptions>(), It.IsAny<System.Threading.CancellationToken>())).ReturnsAsync<UpdateResult>();
var result = eventRepository.UpdateEventAsync(pEvent);
////Assert
result.Should().NotBeNull();
Assert.AreEqual(true, result);
}
below is the code for which i want to write Moq Test
public async Task<bool> UpdateEventAsync(Model.EventDataModel.PlanEvent eventobj)
{
var filter = Builders<Model.EventDataModel.PlanEvent>.Filter.Where(f => f.ID == eventobj.ID);
// TO Do: Use replace instead of update.
var updatestatement = Builders<Model.EventDataModel.PlanEvent>.Update.Set(s => s.IsDeleted, eventobj.IsDeleted)
.Set(s => s.EquipmentID, eventobj.EquipmentID)
.Set(s => s.PlannedStartDateTime, eventobj.PlannedStartDateTime)
.Set(s => s.PlannedEndDatetime, eventobj.PlannedEndDatetime)
.Set(s => s.WorkOrderID, eventobj.WorkOrderID)
.Set(s => s.ResourceID, eventobj.ResourceID)
.Set(s => s.LastUpdatedBy, eventobj.LastUpdatedBy)
.Set(s => s.EventComment, eventobj.EventComment)
.Set(s => s.SiteID, eventobj.SiteID)
.Set(s => s.LastUpdatedDateTime, DateTime.UtcNow.ToString());
UpdateResult updateResult = await _eventContext.PlanEvent.UpdateOneAsync(filter, updatestatement);
return updateResult != null && updateResult.IsAcknowledged && updateResult.ModifiedCount > 0;
}
Either create an instance or mock UpdateResult and return that from the setup
public async Task UpdateEventAsync_Test() {
//...omitted for brevity
var mockUpdateResult = new Mock<UpdateResult>();
//Set up the mocks behavior
mockUpdateResult.Setup(_ => _.IsAcknowledged).Returns(true);
mockUpdateResult.Setup(_ => _.ModifiedCount).Returns(1);
mockEventContext
.Setup(_ => _.PlanEvent.UpdateOneAsync(It.IsAny<FilterDefinition<PlanEvent>>(), It.IsAny<UpdateDefinition<Model.EventDataModel.PlanEvent>>(), It.IsAny<UpdateOptions>(), It.IsAny<System.Threading.CancellationToken>()))
.ReturnsAsync(mockUpdateResult.Object);
//Act
var result = await eventRepository.UpdateEventAsync(pEvent);
//Assert
result.Should().Be(true);
}
Also note that the test needs to be made async to be exercised accurately.

How to simplify transforming entity framework entities to DTOs

I map to a data transformation object when retrieving items from an ASP.NET Web API like so for a list:
public async Task<IList<PromotionDTO>> GetPromotionsList()
{
return await _context.Promotions
.Select(p => new PromotionDTO
{
PromotionId = p.PromotionId,
Is_Active = p.Is_Active,
Created = p.Created,
Title = p.Title,
BusinessName = p.BusinessName,
})
.Where(x => x.Is_Active)
.OrderByDescending(x => x.Created)
.ToListAsync();
}
And like this for getting a single record:
public async Task<PromotionDTO> GetPromotion(int id)
{
return await _context.Promotions
.Select(p => new PromotionDTO
{
PromotionId = p.PromotionId,
Is_Active = p.Is_Active,
Created = p.Created,
Title = p.Title,
BusinessName = p.BusinessName,
})
.Where(x => x.Is_Active && x.PromotionId == id)
.FirstOrDefaultAsync();
}
I'm new to DTO's and I find that I'm using the same DTO transformation code at many places, and was wondering how I can simplify my code to only do this once?
Though it may be enough to map like you've stated, but when your project starts to grow it will just complicated things and cause additional work.
I suggest that you use some kind of mapping library like AutoMapper.
https://github.com/AutoMapper/AutoMapper
static MyRepositoryConstructor()
{
// Define your maps
Mapper.Initialize(cfg => {
cfg.CreateMap<PromotionEntity, PromotionDTO>();
});
}
public async Task<IList<PromotionDTO>> GetPromotionsList()
{
return Mapper.Map<IList<PromotionDTO>>(await _context.Promotions
.Where(x => x.Is_Active)
.OrderByDescending(x => x.Created)
.ToListAsync()
);
}
public async Task<PromotionDTO> GetPromotion(int id)
{
return Mapper.Map<PromotionDTO>(await _context.Promotions
.Where(x => x.Is_Active && x.PromotionId == id)
.FirstOrDefaultAsync()
);
}
One option is to create a method which returns an IQueryable and then use that in each
Private IQueryable<PromotionDTO> Query()
{
return _context.Promotions
.Select(p => new PromotionDTO
{
PromotionId = p.PromotionId,
Is_Active = p.Is_Active,
Created = p.Created,
Title = p.Title,
BusinessName = p.BusinessName,
});
}
public async Task<IList<PromotionDTO>> GetPromotionsList()
{
return await Query()
.Where(x => x.Is_Active)
.OrderByDescending(x => x.Created)
.ToListAsync();
}
public async Task<PromotionDTO> GetPromotion(int id)
{
return await Query()
.Where(x => x.Is_Active && x.PromotionId == id)
.FirstOrDefaultAsync();
}

accessing UI Thread with async / await with Mvvm

I want to pass some contents on the DocumentViewer with progress indicator using Mvvm pattern, this generation will use UiElements after getting data from db asynchrounously.
public async void ProcessReportAsync(){
IsBusy = true;
_reportDal = new ReportDal(_sprocName,_sprocParams);
ReportContainers = new ObservableCollection<ReportContainerViewModel>();
await Task.Run(() => _reportDal.InitReportDal());
ReportDataTable = _reportDal.DataTableReport;
await Task.Run(() => ProcessedElements());
var t3 = Task.Run(() => ProcessPage(_reportPage));
var t4 = Task.Run(() => ProcessContainerData());
await Task.WhenAll(t3, t4);
var p = new PrinterViewModel(this);
// This statement does'nt complete its execuation, which is adding more UIElements
if(DispatcherHelper.UIDispatcher.CheckAccess()) {
DispatcherHelper.UIDispatcher.Invoke(
()=>_document = p.CreateDocument(new Size(p.PrintDialog.PrintableAreaWidth,p.PrintDialog.PrintableAreaHeight))
,DispatcherPriority.Background);
}
// Can't reach this code
IsBusy = false;
}
One nice aspect of async/await is that it takes care of dispatching back to the correct context for you.
public async Task ProcessReportAsync()
{
IsBusy = true;
_reportDal = new ReportDal(_sprocName,_sprocParams);
ReportContainers = new ObservableCollection<ReportContainerViewModel>();
await Task.Run(() => _reportDal.InitReportDal());
ReportDataTable = _reportDal.DataTableReport;
await Task.Run(() => ProcessedElements());
var t3 = Task.Run(() => ProcessPage(_reportPage));
var t4 = Task.Run(() => ProcessContainerData());
await Task.WhenAll(t3, t4);
var p = new PrinterViewModel(this);
_document = p.CreateDocument(new Size(p.PrintDialog.PrintableAreaWidth,p.PrintDialog.PrintableAreaHeight));
IsBusy = false;
}
I suggest you read my async/await intro and my MSDN article on async.