public List<PropertyListDto> GetPropertiesByStatus(GetPropertyInput input)
{
//exception occurs here
var properties = _propertyRepository
.GetAll()
.Include(p => p.Address)
.ToList();
var results = new List<PropertyListDto>(properties.OrderBy(p => p.Id).MapTo<List<PropertyListDto>>());
return results;
}
[AutoMapFrom(typeof(Property))]
public class PropertyListDto : FullAuditedEntityDto
{
public new int Id { get; set; }
public CountyListDto County { get; set; }
public string Priority { get; set; }
public string Dist { get; set; }
public decimal ListingPrice { get; set; }
public string Blk { get; set; }
public AddressDto Address { get; set; }
public string Contact { get; set; }
public string Lot { get; set; }
public decimal Taxes { get; set; }
public string Mls { get; set; }
public ICollection<CommentEditDto> Comments { get; set; }
public int? LegacyId { get; set; }
}
Q : I need to show around 100,000 (1 lakh) data on the Angular UI Grid.But the problem is, above query gives memory exception.So could you tell me how to sort out this issue ? Thanks.
Note : I need to show the data without pagination.So I have selected this UI Grid.
UPDATE :
When I use .AsNoTracking(), then it works fine on the first query.
var properties = _propertyRepository
.GetAll()
.AsNoTracking()
.Include(p => p.Address)
.ToList();
But then the problem is on MapTo line.Could you tell me how to sort it out ? Thanks.
var results = new List<PropertyListDto>(properties.OrderBy(p => p.Id).MapTo<List<PropertyListDto>>());//error is here now
This is the error :
{"Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding."}
Mapping types:
Property_A048C3D093990BB6A086B710BAC90CB35FD4BAB180FC02FA3E90053FE58F20D3 -> ICollection`1
System.Data.Entity.DynamicProxies.Property_A048C3D093990BB6A086B710BAC90CB35FD4BAB180FC02FA3E90053FE58F20D3 -> System.Collections.Generic.ICollection`1[[IP.Comments.Dtos.CommentEditDto,IP.Application, Version=1.7.1.1, Culture=neutral, PublicKeyToken=null]]
Destination path:
List`1[3126].Comments3126[3126].Comments3126[3126]
Source value:
[Property_A048C3D093990BB6A086B710BAC90CB35FD4BAB180FC02FA3E90053FE58F20D3 3166]
UPDATE 2 : Here I have used Automapper to map EF object into Dto object.
I suppose you are initiate two ToList methods since I do not know what MapTo doing.
However instead doing mapping select directly your dto:
var properties = _propertyRepository
.GetAll()
.AsNoTracking()
.Include(p => p.Address).
.Select(s=> new PropertyListDto{
Id = s.Id
CountyListDto = s.CountyListDto
...
})
OP's Answer : Actually I have reduced all the unnecessary data on the above table and now it's having around 1K+ records.So no problem at all now.Cheers :)
Related
I am trying to flatten out my model and I am coming across an issue I can't seem to understand.
Inspection Item Model:
public class InspectionItem
{
public string InspectionItemName { get; set; }
public ICollection<Inspection> Inspections { get; set; }
}
Inspection Model:
public class Inspection
{
public InspectionItem InspectionItem { get; set; }
public string InspectionItemId { get; set; }
public string PassFail { get; set; }
public ICollection<Answer> Answers { get; set; }
public ICollection<InspectionInputAnswer> InspectionInputAnswers { get; set; }
}
The Query:
So my issue is, if an Inspection does not contain a data for BOTH Answers and InspectionInputAnswers, the whole list returns 0 records? If the Inspection contains a record for both it then returns data. I don't understand why my select many clause is working this way? I am trying to flatten Inspections and both Answers/InspectionInputAnswers.
var inspectionItemInspections = await context.InspectionItems
.Include("Inspections")
.Include("Inspections.Answers")
.Include("Inspections.InspectionInputAnswers")
.Where(a => a.InspectionItemTypeId == idFilter)
.SelectMany(x => x.Inspections
.SelectMany(y => y.Answers
.SelectMany(z => y.InspectionInputAnswers,(answer,inputAnswer) => new { answer, inputAnswer })
.Select(d => new {
Date = y.CreatedAt,
InspectionItemName = x.InspectionItemName,
InspectionItemTypeId = x.InspectionItemTypeId,
InspectedById = y.InspectedById,
PassFail = y.PassFail,
QuestionId = d.answer.QuestionId,
ValueMeasured = d.inputAnswer.ValueMeasured
})
)).ToListAsync();
So how can I write this so that the Inspections relationship does not require an entry for both Answers and InspectionInputAnswers?
Thanks!
I have the following query:
var catInclude = _db.Cat
.Where(x => x.ProvId == request.ProvId)
.Include(x => x.CatItems)
.SingleOrDefault(p => p.Id == request.ProvId
cancellationToken: cancellationToken);
As I don't want to get all properties from CatItems with Include(), I have created the following query:
var catSelect = _db.Cat
.Where(x => x.ProvId == request.ProvId)
.Select(p ==> new
{ Provider = p,
Items = p.CatItems.Select(x => new List<CatItems> { new CatItems
{ Id = x.Id, Name = x.Name, Price = x.Price } }
})})
SingleOrDefault(cancellationToken: cancellationToken);
But something is wrong in the 2nd query because here return _mapper.ProjectTo<CatDto>(cat) I get the following error:
Argument 1: cannot convert from '<anonymous type: Db.Entities.Cat Prov, System.Colletions.Generic.IEnumerable<System.Colletions.Generic.List<Models.CatItems> > Items>' to 'System.Linq.IQueryable'
Here is my CatDto:
public class CatDto
{
public int ProvId { get; set; }
public List<CatItems> CatItems { get; set; }
}
Here are my entities:
public class Prov
{
public int Id { get; set; }
public Cat Cat { get; set; }
}
public class Cat
{
public int Id { get; set; }
public int ProvId { get; set; }
public List<CatItems> CatItems { get; set; }
}
public class CatItems
{
public int Id { get; set; }
public int CatId { get; set; }
public DateTime CreatedOn { get; set; }
}
Is there a way to recreate the 2nd query and use it?
Main difference that instead of returning List of CatItems, your code returns IEnumerable<List<CatItems>> for property Items.
So, just correct your query to project to List:
var catSelect = await _db.Cat
.Where(x => x.ProvId == request.ProvId)
.Select(p => new CatDto
{
ProvId = p.ProvId,
Items = p.CatItems.Select(x => new CatItems
{
Id = x.Id,
Name = x.Name,
Price = x.Price
})
.ToList()
})
.SingleOrDefaultAsync(cancellationToken: cancellationToken);
I mean, even the exception is pretty self-explanatory. Nevertheless:
You are performing a .Select(...). It returns an Anonymous type. So, your catSelect is an anonymous type, thus the AutoMapper fails.
The quickest fix is to just cast (Cat)catSelect before mapping.
Or, you can dig deeper into how does AutoMapper play with anonymous types.
I feel like you can make most of the classes inherent Id and why is public cat CAT {get; set;} i thought you were supposed to initialize some kind of value
Multiple answers have led me to the following 2 solutions, but both of them do not seem to be working correctly.
What I have are 2 objects
public class DatabaseAssignment : AuditableEntity
{
public Guid Id { get; set; }
public string User_Id { get; set; }
public Guid Database_Id { get; set; }
}
public class Database : AuditableEntity
{
public Guid Id { get; set; }
public string Name { get; set; }
public string Server { get; set; }
public bool IsActive { get; set; }
public Guid DatabaseClientId { get; set; }
}
Now, the front-end will return all selected Database objects (as IEnumerable) for a given user. I am grabbing all current DatabaseAssignments from the database for the given user and comparing them to the databases by the Database.ID property. My goal is to find the DatabaseAssignments that I can remove from the database. However, my solutions keep returning all DatabaseAssignments to be removed.
if (databases != null)
{
var unitOfWork = new UnitOfWork(_context);
var userDatabaseAssignments = unitOfWork.DatabaseAssignments.GetAll().Where(d => d.User_Id == user.Id);
//var assignmentsToRemove = userDatabaseAssignments.Where(ud => databases.Any(d => d.Id != ud.Database_Id));
var assignmentsToRemove = userDatabaseAssignments.Select(ud => userDatabaseAssignments.FirstOrDefault()).Where(d1 => databases.All(d2 => d2.Id != d1.Database_Id));
var assignmentsToAdd = databases.Select(d => new DatabaseAssignment { User_Id = user.Id, Database_Id = d.Id }).Where(ar => assignmentsToRemove.All(a => a.Database_Id != ar.Database_Id));
if (assignmentsToRemove.Any())
{
unitOfWork.DatabaseAssignments.RemoveRange(assignmentsToRemove);
}
if (assignmentsToAdd.Any())
{
unitOfWork.DatabaseAssignments.AddRange(assignmentsToAdd);
}
unitOfWork.SaveChanges();
}
I think u are looking for an Except extension, have a look at this link
LINQ: Select where object does not contain items from list
Or other way is with contains see below Fiddler link :
https://dotnetfiddle.net/lKyI2F
I'm sure this is dead simple, but I need help ... I'm trying to display a single product in a view, and have this query:
var Product = await (from p in _context.Products
where p.Id == id
select p).FirstOrDefaultAsync();
Then I try to map the result to my viewmodel and return it to the view:
var VMProduct = _mapper.Map<ViewModelProduct, Product>(Product);
return View(VMProduct);
However, I get a build error on the mapping:
"Error CS1503 Argument 1: cannot convert from 'MyStore.Models.Product'
to MyStore.Models.ViewModels.ViewModelProduct'"
This is my entity model,
public class Product
{
public int Id { get; set; }
public string Title { get; set; }
public string Info { get; set; }
public decimal Price { get; set; }
public List<ProductInCategory> InCategories { get; set; }
}
and this is my viewmodel
public class ViewModelProduct
{
public int Id { get; set; }
public string Title { get; set; }
public string Info { get; set; }
public decimal Price { get; set; }
public int SortOrder { get; set; }
public IEnumerable<ViewModelCategoryWithTitle> Categories { get; set; }
public ViewModelProduct(ProductInCategory pic)
{
Id = pic.Product.Id;
Title = pic.Product.Title;
Price = pic.Product.Price;
Info = pic.Product.Info;
SortOrder = pic.SortOrder;
}
public ViewModelProduct() { }
}
This is my mapping profile:
CreateMap<Product, ViewModelProduct>();
CreateMap<ViewModelProduct, Product>();
Edit:
After changing
var VMProduct = _mapper.Map<ViewModelProduct, Product>(Product);
to
var VMProduct = _mapper.Map<Product, ViewModelProduct>(Product);
and adding Mapper.AssertConfigurationIsValid();, I get one step further, and am informed that SortOrder, Categories and InCategories are unmapped.
I'm reluctant to change my viewmodel (too much). Can I make the mapping work with the current viewmodel?
Edit 2:
Apparently, now it works. The unmapped properties are still unmapped, but when I removed Mapper.AssertConfigurationIsValid();, the view rendered just fine.
Note that you can define for each member how it should be mapped. This is necessary if the destination member has a different name than the source member.
If source and destination have different (complex) types, add an additional mapping config between these types.
If the member is not mapped, but set somewhere else (e.g. in the controller), ignore it to prevent an error when checking the configuration with Mapper.AssertConfigurationIsValid().
CreateMap<Product, ViewModelProduct>()
// other members will be mapped by convention, because they have the same name
.ForMember(vm => vm.SortOrder, o => o.Ignore()) // to be set in controller
.ForMember(vm => vm.Categories, o => o.MapFrom(src => src.InCategories));
// needed to resolve InCategories -> Categories
CreateMap<ViewModelCategoryWithTitle, ProductInCategory>();
Also, most of the time it is sufficient to tell Automapper just the destination type you want, and let it resolve which mapping to apply:
var VMProduct = _mapper.Map<ViewModelProduct>(Product);
I'm a bit lost here and I've tried a few different ways to tackle it. So far I'm having a hard time writing out the LINQ to do what I want.
I want to take the user input string which can be multiple keywords split either by whitespace or ",".
This here works grabs the whole search term and compares it to the title in the Post or any tag I may have. I want the user to type in "HTML Preview" which would match a post called, "Preview the World" with the tags "HTML", "CSS", etc....
This query won't work...but I'm trying to modify it so that it does work.
public IPagedList<Post> SearchResultList(string searchTerm, int resultsPerPage, int page)
{
string[] terms = searchTerm.Split(null);
TNDbContext context = DataContext;
return context.Posts
.Include(a => a.Tags)
.Include(b => b.Comments)
.Where(c => (c.Title.Contains(searchTerm) || c.Tags.Any(d => d.Name.StartsWith(searchTerm))) || searchTerm == null)
.OrderByDescending(x => x.Views)
.ToPagedList(page, resultsPerPage);
}
I tried writing this instead of the other "Where" statement
.Where(x => (terms.All(y => x.Title.Contains(y))) || terms == null)
but it keeps throwing this error
Cannot compare elements of type 'System.String[]'. Only primitive types, enumeration types and entity types are supported.
FOR REFERENCE:
public class Post
{
public Post()
{
Tags = new HashSet<Tag>();
Comments = new HashSet<Comment>();
}
public int Id { get; set; }
public string Title { get; set; }
public string UrlTitle { get; set; }
public DateTime Date { get; set; }
public DateTime DateEdited { get; set; }
public string Body { get; set; }
public string Preview { get; set; }
public string PhotoPath { get; set; }
public int Views { get; set; }
//Navigational
public ICollection<Tag> Tags { get; set; }
public ICollection<Comment> Comments { get; set; }
}
public class Tag
{
public Tag()
{
Post = new HashSet<Post>();
}
public int Id { get; set; }
public string Name { get; set; }
public int TimesTagWasUsed { get; set; }
//Navigational
public ICollection<Post> Post { get; set; }
}
You need to start with a base query, and then keep adding where clauses to it for each search term. Try this:
TNDbContext context = DataContext;
//Create the base query:
var query = context.Posts
.Include(a => a.Tags)
.Include(b => b.Comments)
.OrderByDescending(x => x.Views);
//Refine this query by adding "where" filters for each search term:
if(!string.IsNullOrWhitespace(searchTerm))
{
string[] terms = searchTerm.Split(" ,".ToCharArray(),
StringSplitOptions.RemoveEmptyEntries);
foreach(var x in terms)
{
string term = x;
query = query.Where(post => (post.Title.Contains(term) ||
post.Tags.Any(tag => tag.Name.StartsWith(term))));
}
}
//Run the final query to get some results:
var result = query.ToPagedList(page, resultsPerPage);
return result;
You can nest queries with additional 'from' statements, so something like this should work:
var list = (from post in context.Posts.Include(a => a.Tags).Include(b => b.Comments)
from term in terms
where post.Title.Contains(term) || post.Tags.Any(d => d.Name.StartsWith(term))
select post).OrderByDescending(x => x.Views);