Relations with DbQuery - asp.net-core

I have this Participant model DbSet<Participants>:
public class Participant {
public Guid Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int IsCaptain { get; set; }
public Guid TeamId { get; set; }
[ForeignKey("TeamId")]
public Team Team { get; set; }
}
And this ParticipantDataView DbQuery<ParticipantsDataView>:
public class ParticipantDataView {
public Guid Id { get; set; } // = Participant.Id
public double? FirstWeight { get; set; }
public double? LastWeight { get; set; }
public double? WeightLoss => FirstWeight - LastWeight;
public Participant Participant { get; set; }
}
DbContext:
public class DBContext : DbContext {
public DBContext(DbContextOptions<DBContext> options) : base(options) {}
public DbSet<Participant> Participants { get; set; }
public DbQuery<ParticipantDataView> ParticipantsDataView { get; set; }
}
My query:
Participants = await _context.ParticipantsDataView
.Include(p => p.Participant)
.ThenInclude(t => t.Team)
.Where(p => p.Participant.Status == 1 && p.Participant.Team.Status == 1).OrderBy(p => p.WeightLoss)
.AsNoTracking()
.ToListAsync();
The error:
SqlNullValueException: Data is Null.
This method or property cannot be called on Null values.
Every item in ParticipantDataView has a match in Participants so I don't know why I get this error?

Related

Eager loading use Include got error in .Net

I'd like to display the 'ApplicationRole' Name with the 'ApplicationUser' data together using Eager loading.
here is my ApplicationUser
public class ApplicationUser : IdentityUser
{
public string? Name { get; set; }
public string? Department { get; set; }
public bool IsDeleted { get; set; }
public string RoleId { get; set; }
public virtual ApplicationRole Role { get; set; } = new ApplicationRole();
}
public class ApplicationUserDTO
{
public string Id { get; set; }
public int UserId { get; set; }
public string Name { get; set; }
public string UserName { get; set; }
// Foreign Key
public string RoleId { get; set; }
public virtual ApplicationRoleDTO Role { get; set; } = new ApplicationRoleDTO();
}
here is ApplicationRole
[NotMapped]
public class ApplicationRole : IdentityRole
{
public string Id { get; set; }
public string Name { get; set; }
//[InverseProperty(nameof(ApplicationUser.Role))]
public virtual ICollection<ApplicationUser> Users { get; set; } = new List<ApplicationUser>();
}
public class ApplicationRoleDTO
{
public string Id { get; set; }
public string Name { get; set; }
public virtual ICollection<ApplicationUserDTO> Users { get; set; } = new List<ApplicationUserDTO>();
}
and here is the UserRepository
public async Task<IEnumerable<ApplicationUser>> GetAllUsersAsync()
{
//return await _dbContext.User.Where(u => u.IsDeleted == false).ToListAsync();
return await _dbContext.User.Include(u => u.Role).Where(u => u.IsDeleted == false).ToListAsync();
}
public async Task<ApplicationUser> GetUserAsync(string id)
{
return await _dbContext.User.Where(u => u.Id == id).Where(u => u.IsDeleted == false).FirstOrDefaultAsync();
}
But when I use the 'Include' keyword it show this error
When I try to use the string "Role", it also show error
public async Task<IEnumerable<ApplicationUser>> GetAllUsersAsync()
{
return await _dbContext.User.Include("Role").Where(u => u.IsDeleted == false).ToListAsync();
}
Here is the error show

How can I Get the results of the nested query in the form of entities with EF

I have some models in my project:
**Model ServiceDeliveryDoc**
public string Id { get; set; }
public string PartnerDocId { get; set; }
public DateTime Date { get; set; }
public decimal Cost { get; set; }
public string LegalEntityId { get; set; }
[ForeignKey("LegalEntityId")]
[InverseProperty("ServiceDeliveryDoc")]
public LegalEntity LegalEntity { get; set; }
[InverseProperty("ServiceDeliveryDoc")]
public ICollection<ServiceRegistryToServiceDeliveryDoc> ServiceRegistryToServiceDeliveryDoc { get; set; }
**Model ServiceRegistry**
public string Id { get; set; }
public DateTimeOffset Date { get; set; }
public decimal Cost { get; set; }
[InverseProperty("ServiceRegistry")]
public ICollection<ServiceRegistryToServiceDeliveryDoc> ServiceRegistryToServiceDeliveryDoc { get; set; }
**Model ServiceRegistryToServiceDeliveryDoc**
public string Id { get; set; }
public string ServiceRegistryId { get; set; }
public string ServiceDeliveryDocId { get; set; }
[ForeignKey("ServiceDeliveryDocId")]
[InverseProperty("ServiceRegistryToServiceDeliveryDoc")]
public ServiceDeliveryDoc ServiceDeliveryDoc { get; set; }
[ForeignKey("ServiceRegistryId")]
[InverseProperty("ServiceRegistryToServiceDeliveryDoc")]
public ServiceRegistry ServiceRegistry { get; set; }
I write some nested query in SQL to get ServiceDeliveryDoc with
LegalEntity, filtered by ServiceRegistryId:
SELECT ReturnsTable.[Id]
,ReturnsTable.[PartnerDocId]
,ReturnsTable.[Date]
,ReturnsTable.[Cost]
,ReturnsTable.[LegalEntityId]
,LegalEntityTable.[Name]
,ReturnsTable.[DocProcessId]
FROM [Vishnya].[dbo].[ServiceDeliveryDoc] as ReturnsTable
left join [Vishnya].[dbo].[LegalEntity] as LegalEntityTable
on ReturnsTable.[LegalEntityId] = LegalEntityTable.[Id]
where ReturnsTable.Id in ( select ServiceDeliveryDocId
from ServiceRegistry_To_ServiceDeliveryDoc
where ServiceRegistryId = #ServiceRegistryId)
How I can recieve simular result, using Enity framework?
From your SQL query and the model design , there is a one-to-one relationship between ServiceDeliveryDoc and LegalEntity , many-to-many relationship between ServiceDeliveryDoc and ServiceRegistry . For loading related data , you could use include like below:
var result = _context.ServiceDeliveryDoc
.Include(sd => sd.LegalEntity)
.Where(sd =>
_context.ServiceRegistryToServiceDeliveryDoc
.Where(srt => srt.ServiceRegistryId == "101")
.Select(srt => srt.ServiceDeliveryDocId)
.Contains(sd.Id)
)
.Select(sd => new
{
sd.Id,sd.PartnerDocId , sd.Date,sd.Cost,sd.LegalEntityId, sd.LegalEntity.Name
}).ToList();
DbContext
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<ServiceRegistryToServiceDeliveryDoc>()
.HasOne(sr => sr.ServiceDeliveryDoc)
.WithMany(sd => sd.ServiceRegistryToServiceDeliveryDoc)
.HasForeignKey(sr => sr.ServiceDeliveryDocId);
modelBuilder.Entity<ServiceRegistryToServiceDeliveryDoc>()
.HasOne(sr => sr.ServiceRegistry)
.WithMany(sd => sd.ServiceRegistryToServiceDeliveryDoc)
.HasForeignKey(sr => sr.ServiceRegistryId);
}

Convert SQL query to Entity Framework which used AggregateFunctions and Where clause

How can I convert this query to Entity Framework?
SQL query:
SELECT Fullname, SUM(CoinCount+DiamondCount) AS GeneralPoint
FROM Students, Groups
WHERE Students.GroupId = Groups.Id AND Groups.Name = 'FSDA_1813_az'
GROUP BY Fullname
ORDER BY GeneralPoint
Entity:
public class Student
{
public int Id { get; set; }
public int GroupId { get; set; }
public string Fullname { get; set; }
public Nullable<int> DiamondCount { get; set; }
public Nullable<int> CoinCount { get; set; }
public string Phone { get; set; }
public string Address { get; set; }
public string Education { get; set; }
public string Email { get; set; }
public System.DateTime Birthdate { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public Nullable<System.DateTime> LastVisited { get; set; }
public string Facebook { get; set; }
public string Linkedin { get; set; }
public string SocialMedia { get; set; }
public byte[] Photo { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Comment> Comments { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Exam> Exams { get; set; }
public virtual Group Group { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Point> Points { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<StudentHomework> StudentHomeworks { get; set; }
}
UserRepository:
public ICollection<Student> GetUsersForGroup(string group)
{
using (var db = new EFContext())
{
var temp = db.Students.Where(x => x.Group.Name == group).ToList();
// I have to sort students in group by their DiamondCount+CoinCount as new GeneralCount
temp = temp.OrderBy(x => );
}
}
I have to sort students for their general point (DiamondCount+CoinCount).
But I can't send LINQ query by using Entity Framework. How can I do this?
Not tested but it should work:
var result = db.Students.Where(x => x.Group.Name == group)
.GroupBy(g => g.Fullname)
.Select(i => new
{
FullName = i.Key,
GeneralPoint = i.Sum(s => s.DiamondCount + s.CoinCount)
})
.OrderBy(o => o.GeneralPoint)
.ToList();

Get Error : Entity type 'Course' is defined with a single key property, but 2 values were passed to the 'DbSet.Find' method

I have a GenericRepository,Which CourseRepository inherits from it, and Entities returns a list of courses
public class CourseRepository : GenericRepositories<Course>, ICourseRepository
{
public CourseRepository(LearningSiteDbContext Context) : base(Context)
{
}
}
public class GenericRepositories<TEntity> : IGenericRepositories<TEntity> where TEntity : class, IEntity,new()
{
protected readonly LearningSiteDbContext context;
public DbSet<TEntity> Entities { get; set; }
public GenericRepositories(LearningSiteDbContext Context)
{
context = Context;
Entities = context.Set<TEntity>();
}
}
But When I run this handler In Razor Page
public async Task OnGetAsync(int Id, CancellationToken cancellationToken)
{
var selectedCourse = await courseRepository.Entities.FindAsync(Id,cancellationToken);
Model = mapper.Map<CourseEditVm>(selectedCourse);
}
I get the following error :
Entity type 'Course' is defined with a single key property, but 2 values were passed to the 'DbSet.Find' method
And this is Course entity class
public class Course
{
public Course()
{
}
public Course(DateTime CreateDate)
{
this.CreateDate = CreateDate;
}
public int Id {get;set;}
public string CourseTitle { get; set; }
public string CourseDescription { get; set; }
public decimal CoursePrice { get; set; }
public string ImageName { get; set; }
public string DemoFileName { get; set; }
public DateTime CreateDate { get; set; }
public DateTime? UpdateDate { get; set; }
public bool IsDeleted { get; set; }
//Foreign key
public int? CourseStatusId { get; set; }
public int? CourseLevelId { get; set; }
public Guid? CustomUserId { get; set; }
public int? CourseGroupId { get; set; }
//Navigations
public CourseStatus CourseStatus { get; set; }
public CourseLevel CourseLevel { get; set; }
public CustomUser CustomUser { get; set; }
public CourseGroup CourseGroup { get; set; }
public ICollection<CourseEpisod> CourseEpisods { get; set; }
public ICollection<Keyword> Keywordkeys { get; set; }
}
And it's Course Config
class CourseConfig : IEntityTypeConfiguration<Course>
{
public void Configure(EntityTypeBuilder<Course> builder)
{
builder.HasKey(c => c.Id);
builder.Property(c => c.Id).ValueGeneratedOnAdd();
builder.Property(c => c.CourseTitle).HasMaxLength(50);
builder.Property(c => c.CourseDescription).HasMaxLength(400);
builder.Property(c => c.ImageName).HasMaxLength(255);
builder.Property(c => c.DemoFileName).HasMaxLength(255);
//Relations
builder.HasMany(c => c.Keywordkeys).WithOne(c => c.Course).HasForeignKey(c => c.CourseId);
builder.HasOne(c => c.CustomUser).WithMany(c => c.Courses).HasForeignKey(c => c.CustomUserId);
}
}
But when I run this code, I will no longer receive this error
var selectedCourse = await courseRepository.Entities.FirstOrDefaultAsync(c => c.Id == Id, cancellationToken);
What is the cause of this error? Is my code wrong? How should I fix this error?
You are using the wrong method, if you check here
FindAsync you can see that if you want to pass a cancellation token, you need to pass your keys as an array like this
.FindAsync(new object[]{id}, cancellationToken);

Passing data to View using ViewModel in ASP.NET Core

SOLUTION:
ParticipantsWithData = await _context.Participants.Select(p => new ParticipantWithData {
Participant = p,
Team = p.Teams,
FirstWeight = p.ParticipantData.Where(pd => pd.ParticipantId == p.Id).OrderBy(x => x.Date).FirstOrDefault(),
LastWeight = p.ParticipantData.Where(pd => pd.ParticipantId == p.Id).OrderByDescending(x => x.Date).FirstOrDefault()
}).ToListAsync();
And then the model:
public class ParticipantWithData {
public Participant Participant { get; set; }
public Team Team { get; set; }
public ParticipantData FirstWeight { get; set; }
public ParticipantData LastWeight { get; set; }
}
That way I can do x.FirstWeight.Date or x.FirstWeight.Weight when looping through Participants (see the ParticipantData model below),
QUESTION:
How can I use this in my view?
var query = await _context.Participants.Select(p => new {
Participant = p,
Team = p.Teams,
FirstWeight = p.ParticipantData.OrderBy(x => x.Date).FirstOrDefault(),
LastWeight = p.ParticipantData.OrderByDescending(x => x.Date).FirstOrDefault()
}).ToListAsync();
If possible, I'd like to make it a strongly typed model, but I don't know how to do that. All I've tried so far doesn't work.
The Participant model:
public class Participant {
public Guid Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public Guid TeamId { get; set; }
[ForeignKey("TeamId")]
public Team Teams { get; set; }
public IList<ParticipantData> ParticipantData { get; set; }
}
The ParticipantData model:
public class ParticipantData {
public Guid Id { get; set; }
public double? Weight { get; set; }
public DateTime Date { get; set; }
public Guid ParticipantId { get; set; }
public Participant Participants { get; set; }
}
The new model I'm working on:
public class ParticipantWithData {
public Participant Participant { get; set; }
public Team Team { get; set; }
public ParticipantData ParticipantData { get; set; }
public double? FirstWeight { get; set; }
public double? LastWeight { get; set; }
}
Maybe I'm way off..?
Write your ParticipantViewModel as follows:
public class ParticipantViewModel
{
public Participant Participant { get; set; }
public Team Team { get; set; }
public double? FirstWeight { get; set; }
public double? LastWeight { get; set; }
}
Then in the query:
var query = await _context.Participants.Inculde(p => p.Teams)
.Include(p => p.ParticipantData).Select(p => new ParticipantViewModel
{
Participant = p,
Team = p.Teams,
FirstWeight = p.ParticipantData.Select(pd => pd.Weight).OrderBy(x => x.Date).FirstOrDefault(),
LastWeight = p.ParticipantData.Select(pd => pd.Weight).OrderByDescending(x => x.Date).FirstOrDefault()
}).ToListAsync();
Note: I didn't see your ParticipantData model but I have answered with assumption so there may be some changes according to your actual data and requirement.