How to get all columns' max, min, mean values - entity-framework

I am trying to get max, min and mean of the values with using
context.SystemUser
.Include(x => x.Stores)
.ThenInclude(a => a.StoreStockDetail)
.Where(b => b.UserName == userName)
.Select(c => new
{
/*max, min, mean values of columns of StoreStockDetail*/
});
public class SystemUser
{
public int Id { get; set; }
public virtual List<Store> Stores { get; set; }
public SystemUser()
{
this.Stores = new List<Store>();
}
}
public class Store
{
public int Id { get; set; }
public virtual StoreStockDetail StoreStockDetail { get; set; }
}
public class StoreStockDetail
{
public int Id { get; set; }
public int BackStore { get; set; }
public int FrontStore { get; set; }
public int ShoppingWindow { get; set; }}
public int StoreId { get; set; }
public virtual Store Store { get; set; }
}
I need to have max, min and mean report of the columns BackStore, FrontStore and ShoppingWindow columns.
Thank you

Instead of using a sequence of LINQ expressions, you could flatten the list of Stores in the SystemUser first and then use the result to find max, min and average. Try this:
var stores = context.SystemUser
.Include(x => x.Stores)
.ThenInclude(a => a.StoreStockDetail)
.Where(b => b.UserName == userName).SelectMany(user => user.Stores);
var report = new
{
FrontStoreMin = stores.Min(store => store.StoreStockDetail.FrontStore),
FrontStoreMax = stores.Max(store => store.StoreStockDetail.FrontStore),
FrontStoreMean = stores.Average(store => store.StoreStockDetail.FrontStore),
// do the same for BackStore and ShoppingWindow
};

Related

EF Select Grandparent for Grandchildren

Class Brands, Models, Generations, Modification
How to get all Brands for ModificationName == "ACK"
public class Brand
{
public Brand()
{
this.Models = new HashSet<Model>();
}
public int BrandId { get; set; }
public virtual ICollection<Model> Models { get; set; }
}
public class Model
{
public Model()
{
this.Generations = new HashSet<Generation>();
}
public virtual ICollection<Generation> Generations { get; set; }
public int? BrandId { get; set; }
public virtual Brand Brand { get; set; }
}
public class Generation
{
public Generation()
{
this.Modifications = new HashSet<Modification>();
}
public int GenerationId { get; set; }
public virtual ICollection<Modification> Modifications { get; set; }
public int? ModelId { get; set; }
public virtual Model Model { get; set; }
}
public class Modification
{
public int ModificationId { get; set; }
public string ModificationName { get; set; }
public int? GenerationId { get; set; }
public virtual Generation Generation { get; set; }
}
Another approach could be to use the Join operator. For example>
from currentBrand in Context.Brand
join currentModel in context.Model on currentBrand.Id equals currentModel.BrandId
join currentGeneration in context.Generations on currentGeneration.ModelId equals currentModel.id
join currentModeification in context.Modification on currentModeification.GenerationId equals currentGeneration .Id
Where currentModeification.ModificationName == "ACK"
Trick here is to use SelectMany method.
var query =
from b in ctx.Brands
where b.Models
.SelectMany(m => m.Generations.SelectMany(g => g.Modifications))
.Where(m => m.ModificationName == "ACK").Any()
select b;
UPDATE with includes
It will work only with EF Core 5
var query =
from b in ctx.Brands
.Include(b => b.Models)
.ThenInclude(g => g.Generations)
.ThenInclude(m => m.Modifications.Where(x => x.ModificationName == "ACK"))
where b.Models
.SelectMany(m => m.Generations.SelectMany(g => g.Modifications))
.Where(m => m.ModificationName == "ACK").Any()
select b;

Entity Framework Core 3 : Pulling data from multiple sources using join

I basically have three tables that I need to query information to get PersonNotes. I am using Entity Framwork Core 3.
Person Table
PersonNote Table
PersonNoteAttachment Table
One person can have many personnotes and one personnote can contain many PersonNoteAttachment.
I need Person table to get the FirstName and LastName which is mapped to the AuthorName in the PersonNote User data model. You can see the mapping section which shows the mapping.
DataModels
namespace Genistar.Organisation.Models.DataModels
{
[Table(nameof(PersonNote), Schema = "common")]
public class PersonNote
{
public int Id { get; set; }
public int PersonId { get; set; }
[ForeignKey("PersonId")]
public Person Person { get; set; }
public string Note { get; set; }
public int AuthorId { get; set; }
[ForeignKey("AuthorId")]
public Person Author { get; set; }
public string CreatedBy { get; set; }
public DateTime Created { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime RecordStartDateTime { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime RecordEndDateTime { get; set; }
}
}
namespace Genistar.Organisation.Models.DataModels
{
[Table(nameof(PersonNoteAttachment), Schema = "common")]
public class PersonNoteAttachment
{
public int Id { get; set; }
public int PersonNoteId { get; set; }
[ForeignKey("PersonNoteId")]
public PersonNote PersonNote { get; set; }
public string Alias { get; set; }
public string FileName { get; set; }
public string MimeType { get; set; }
public int Deleted { get; set; }
public string CreatedBy { get; set; }
public DateTime Created { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime RecordStartDateTime { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public DateTime RecordEndDateTime { get; set; }
}
}
User Model - This is the model that I am returning to the client application
namespace Genistar.Organisation.Models.User
{
[Table(nameof(PersonNote), Schema = "common")]
public class PersonNote
{
public int Id { get; set; }
public int PersonId { get; set; }
public string Note { get; set; }
public int AuthorId { get; set; }
public string AuthorName { get; set; }
public string CreatedBy { get; set; }
public DateTime Created { get; set; }
}
}
Mapping
CreateMap<Genistar.Organisation.Models.DataModels.PersonNote, Genistar.Organisation.Models.User.PersonNote>()
.ForMember(t => t.Id, opt => opt.MapFrom(s => s.Id))
.ForMember(t => t.PersonId, opt => opt.MapFrom(s => s.PersonId))
.ForMember(t => t.AuthorName, opt => opt.MapFrom(s => s.Author.FirstName + " " + s.Author.LastName))
.ForMember(t => t.Note, opt => opt.MapFrom(s => s.Note))
.ForMember(t => t.AuthorId, opt => opt.MapFrom(s => s.AuthorId))
.ForMember(t => t.CreatedBy, opt => opt.MapFrom(s => s.CreatedBy))
.ForMember(t => t.Created, opt => opt.MapFrom(s => s.Created));
The following query works but is only pulling data from Person and PersonNote table. I am looking at getting the PersonNoteAttachment as well. How do I do that ? I would basically need FileName & MimeType
field populated in User.PersonNote model. If you see above I have created a PersonNoteAttachment data model
Repository
public IQueryable<PersonNote> GetPersonNotes(int personId)
{
var personNotes = _context.PersonNotes.Include(x => x.Person).Include(x=> x.Author).Where(p => p.PersonId == personId);
return personNotes;
}
API :
[FunctionName(nameof(GetPersonNote))]
[UsedImplicitly]
public Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "person-note/{id}")] HttpRequest req,
int id) => _helper.HandleAsync(async () =>
{
//await _helper.ValidateRequestAsync(req, SecurityPolicies.ViewNotes);
var personNotes = await _organisationRepository.GetPersonNotes(id).ProjectTo<PersonNote>(_mapper.ConfigurationProvider).ToListAsync();
return new OkObjectResult(personNotes);
});
My approach was to do it the following way in the repository but I need to return the PersonNote datamodel in the repository. I cannot add those additional fields in the model because it say invalid columns.How do I approach this ?
var personNotes = _context.PersonNotes
.Include(x => x.Person)
.Include(x => x.Author)
.Where(p => p.PersonId == personId)
.Join(_context.PersonNotesAttachments, c => c.Id, cm => cm.PersonNoteId, (c, cm) => new
{
cm.PersonNote.Id,
cm.PersonNote.PersonId,
cm.PersonNote.Person,
cm.PersonNote.Note,
cm.FileName,
cm.MimeType,
cm.Alias,
cm.PersonNote.AuthorId,
cm.PersonNote.CreatedBy,
cm.PersonNote.Created
});
I have resolved the issue
I just had to add the following line in PersonNote datamodel
public PersonNoteAttachment PersonNoteAttachment { get; set; }
Added the new fields to the PersonNote usermodel and did the following mapping
.ForMember(t => t.FileName, opt => opt.MapFrom(s => s.PersonNoteAttachment.FileName))
.ForMember(t => t.MimeType, opt => opt.MapFrom(s => s.PersonNoteAttachment.MimeType))
.ForMember(t => t.Alias, opt => opt.MapFrom(s => s.PersonNoteAttachment.Alias))

EF6 Ignoring related data

Scenario
public class Product : Entity, IAggregateRoot
{
public string Name { get; set; }
public string Dimension { get; set; }
public decimal Volume { get; set; }
public bool Featured { get; set; }
public Farm Farm { get; set; }
public int FarmId { get; set; }
/// <summary>
/// Sell Price
/// </summary>
public decimal BidPrice { get; set; }
public int QuantityAvaliable { get; set; }
public ICollection<Image> Images { get; set; }
public string Description { get; set; }
public Category Category { get; set; }
public int CategoryId { get; set; }
public DateTime Created { get; set; }
public DateTime? Modified { get; set; }
}
public class Category : Entity, IAggregateRoot
{
public string Title { get; set; }
public string CategoryImage { get; set; }
public Category Parent { get; set; }
public DateTime Created { get; set; }
public DateTime? Modified { get; set; }
}
Relationship setup
public class ProductMap : EntityTypeConfiguration<Product>
{
public ProductMap()
{
HasKey(x => x.Id);
Property(x => x.Created).HasColumnType("DateTime");
Property(x => x.Modified).HasColumnType("DateTime");
Property(x => x.BidPrice).HasColumnType("Decimal");
#region RELATIONSHIP
//BelongsTo
HasRequired(x => x.Farm);
HasRequired(x => x.Category);
HasMany(x => x.Images);
#endregion
}
So I have this two model where I need to bring the data from Product model with Category information
I have checked my database, the data is consistent, the Product record have the FK for the Category record.
but when I try to get Product Data using EF6, the category information doesnt come, I get a null object.
Because of = () =>
{
_product = _repository.Find(p => p.Id == 1, p => p.Category);
};
It should_not_be_bull = () =>
_product.Category.ShouldNotBeNull();
the response from data base is for Category is null. but the record is there.
I had it working properly before. for some random magic reason it just stop working.
THE FIND method
public virtual TEntity Find(Expression<Func<TEntity, bool>> predicate = null, params Expression<Func<TEntity, object>>[] includes)
{
var set = CreateIncludedSet(includes);
return (predicate == null) ?
set.FirstOrDefault() :
set.FirstOrDefault(predicate);
}
the CreateIncludeSet
private IDbSet<TEntity> CreateIncludedSet(IEnumerable<Expression<Func<TEntity, object>>> includes)
{
var set = CreateSet();
if (includes != null)
{
foreach (var include in includes)
{
set.Include(include);
}
}
return set;
}
the CreateSet method
private IDbSet<TEntity> CreateSet()
{
return Context.CreateSet<TEntity>();
}
MY DbContext implementation is here
https://github.com/RobsonKarls/FreedomWebApi/blob/dev/Source/Freedom.Infrastructure.DataAccess/Factories/FreedomDbContext.cs
all project is there too for further analisys
any help is valuable.
Thank you
The problem in your code is in this line in CreateIncludedSet method:
set.Include(include);
Yes, you include the data but you do not change you set. You should change it to something like:
set = set.Include(include);
Your code is a bit unclear, but try something like this....
_product = _repository.Include(p => p.Category).SingleOrDefault(x => x.Id == 1);
also see...
https://stackoverflow.com/a/7348694/6200410

Entity Framework Many To Many returns null

I have Many To Many relationship defined and when I try to query for the records that should be in the map I get null.
public class Record
{
public int RecordId { get; set; }
public DateTime DateRecordCreated { get; set; }
public ICollection<Street> Streets { get; set; }
public ICollection<Street> CrossStreets { get; set; }
}
public class RecordMap : EntityTypeConfiguration<Record>
{
public RecordMap()
{
// Primary Key
this.HasKey(t => t.RecordId);
this.HasMany(r => r.Streets)
.WithMany(c => c.Records)
.Map(sl =>
{
sl.ToTable("StreetRecordMap", "dbo");
sl.MapLeftKey("RecordId");
sl.MapRightKey("StreetId");
});
this.HasMany(r => r.CrossStreets)
.WithMany(c => c.AnotherRecord)
.Map(sl =>
{
sl.ToTable("AnotherStreetRecordMap", "dbo");
sl.MapLeftKey("RecordId");
sl.MapRightKey("StreetId");
});
this.Property(t => t.DateRecordCreated).IsRequired();
}
}
public class House : Record
{
public string HouseNumber { get; set; }
public string StreeName { get; set; }
public int ZipCode { get; set; }
}
public class Street
{
public int StreetId { get; set; }
public string StreetName { get; set; }
public ICollection<Record> Records { get; set; }
public ICollection<Record> AnotherRecord { get; set; }
}
Now when I run the following query below I get houses.CrossStreets as null, I tried adding enabling lazy loading and had the same out come.
public static void GetRecords()
{
using (var context = new SandboxContext())
{
var entities = context.Houses.Include(r => r.CrossStreets);
var houses = entities.ToList();
}
}

How to combine multiple table using Linq?

public class JobDescription
{
public int JobDescriptionID { get; set; }
//
public virtual List<Image> Image { get; set; }
}
public class Image
{
public int ImageID { get; set; }
[Required]
public int JobDescriptionID { get; set; }
[ForeignKey("JobDescriptionID")]
public virtual JobDescription JobDescription { get; set; }
public virtual List<ImageSection> ImageSection { get; set; }
}
public class ImageSection
{
public int ImageSectionID { get; set; }
//
public int ImageID { get; set; }
[ForeignKey("ImageID")]
public virtual Image Image { get; set; }
public virtual DigitalSection DigitalSection { get; set; }
}
public class DigitalSection
{
public int DigitalSectionID { get; set; }
public int ImageSectionID { get; set; }
[ForeignKey("ImageSectionID")]
public virtual ImageSection ImageSection { get; set; }
public virtual VerifiedSection VerifiedSection { get; set; }
}
public class VerifiedSection
{
public int VerifiedSectionID { get; set; }
public string DigitizedText { get; set; }
public int DigitalSectionID { get; set; }
[ForeignKey("DigitalSectionID")]
public virtual DigitalSection DigitalSection { get; set; }
}
I am using CodeFirst approach and I have JobDscriptionID. Now i want to retireve all the DigitizedText from VerifiedSection Table. How to do it ?
Try this :
var result = contetx.VerifiedSection
.Where(V => V.DigitalSection.ImageSection.Image.JobDescription.JobDescriptionID == 1)
.Select(V => V.DigitizedText);
Alternately you could also use Join
var result = context.VerifiedSection.Join(context.DigitalSection.Join(
(context.ImageSection.Join
(context.Image.Join
(context.JobDescription.Where(J=> .JobDescriptionID == 1)), I=> I.JobDescriptionID, J => J.JobDescriptionID , (I,J) => I)
IS => IS.ImageID, I=> I.ImageID, (IS,I) => IS)
D => D.ImageSectionID, IS => IS.ImageSectionID , (D,IS) => D)
V => V.DigitalSectionID, D => D.DigitalSectionID, (V,D) => V.DigitizedText);
Good Luck !!
var query = (from image in Context.Image
Where image.JobDescriptionID == id
select image.ImageID).SingleOrDefault();
var query2 = (from select in Context.ImageSection
Where select.ImageID == query
select select.ImageSectionID).SingleOrDefault();
var query3 = (from digital in Context.DigitalSection
Where digital.ImageSectionID == query2
select digital.DigitalSectionID).SingleOrDefault();
var query4 = from text in Context.VerifiedSection
Where text.VerifiedSection == query3
select select.DigitizedText;
Kundan Singh Chouhan gave you a better answer, but perhaps you'd like to do it the "Queries" way.