Given the data below, I am trying to write a LINQ statement that will group by ListOfAdmin by id so it will only display one user. I am also checking that the count is not 0. The record one has no ListOfAdmin so that Count==0 should return null but it is displaying records for ListOfAdmin . Also
once I add //.GroupBy(f => f.id) I get the error Cannot implicitly convert type 'System.Collections.Generic.List
All of the other section is working fine.
Once I add ListOfSubscription with no record for ListOfAdmin I get the error
LINQPad Example
class Subscription
{
public int SubscriptionId { get; set; }
public int ParentProductId { get; set; }
public string ParentProductName { get; set; }
public string ChildProductName { get; set; }
public int ChildProductId { get; set; }
public int GroupId { get; set; }
public DateTime? EndDate { get; set; }
public List<admin> ListOfAdmin { get; set; }
}
class SubscriptionViewModel
{
public int SubscriptionId { get; set; }
public int ParentProductId { get; set; }
public string ParentProductName { get; set; }
public string SubscriptionIds { get; set; }
public int GroupId { get; set; }
public List<SubscriptionChildViewModel> ListOfSubscriptionChild { get; set; }
public List<AdminViewModel> ListOfAdmin { get; set; }
}
class SubscriptionChildViewModel
{
public string ChildProductName { get; set; }
public int ChildProductId { get; set; }
}
class AdminViewModel
{
public int id { get; set; }
public string name { get; set; }
}
class admin
{
public int id { get; set; }
public string name { get; set; }
}
void Main()
{
List<Subscription> ListOfSubscription = new List<Subscription>();
List<admin> ListOfAdmin = new List<admin>();
ListOfSubscription.Add(new Subscription() { SubscriptionId = 1, ParentProductId = 4, ChildProductId = 4, ParentProductName = "Product 1", ChildProductName = "Product 1", GroupId = 362,ListOfAdmin= ListOfAdmin });
ListOfAdmin.Clear();
ListOfAdmin.Add(new admin() { id = 1, name= "Mike"});
ListOfAdmin.Add(new admin() { id = 2, name = "Bill" });
ListOfSubscription.Add(new Subscription() { SubscriptionId = 2, ParentProductId = 114, ChildProductId = 1, ParentProductName = "Product 2", ChildProductName = "Product 3", GroupId = 1, ListOfAdmin= ListOfAdmin });
ListOfSubscription.Add(new Subscription() { SubscriptionId = 3, ParentProductId = 114, ChildProductId = 2, ParentProductName = "Product 2", ChildProductName = "Product 4", GroupId = 1, ListOfAdmin = ListOfAdmin });
var groupedSubscriptions = ListOfSubscription.GroupBy(u => u.GroupId);
var result = groupedSubscriptions.Select(grp1 => new
{
GroupId = grp1.Key,
Subscriptions = grp1.GroupBy(subscr => new
{
subscr.ParentProductId,
subscr.ParentProductName,
//subscr.ListOfAdmin
})
.Select(grp2 => new SubscriptionViewModel
{
GroupId = grp1.Key,
ParentProductId = grp2.Key.ParentProductId,
ParentProductName = grp2.Key.ParentProductName,
SubscriptionIds = string.Join(",", grp2.Select(y => y.SubscriptionId)),
ListOfSubscriptionChild = grp2
.Where(subsc => subsc.ChildProductId != grp2.Key.ParentProductId)
.Select(subsc => new SubscriptionChildViewModel
{
ChildProductId = subsc.ChildProductId,
ChildProductName = subsc.ChildProductName
})
.ToList(),
ListOfAdmin = (grp2.SelectMany(y => y.ListOfAdmin).Count()) == 0 ? null : grp2.SelectMany(y => y.ListOfAdmin)
.Select(a => new AdminViewModel
{
id = a.id,
name = a.name
})
//.GroupBy(f => f.id)
.ToList(),
})
});
var x = result.SelectMany((s => s.Subscriptions));
Console.Write(x);
}
Updated: using List<IGrouping<int, AdminViewModel>> I am getting dups.
Let's take a look at the exact error: Cannot implicitly convert type 'System.Collections.Generic.List<System.Linq.IGrouping<int,Program.AdminViewModel>>' to 'System.Collections.Generic.List<Program.AdminViewModel>'.
It is pretty clear: you are trying to assign a value (of type List<IGrouping<int,Program.AdminViewModel>>) that is not of the expected type (List<Program.AdminViewModel>).
You can remedy this by changing SubscriptionViewModel, so that ListOfAdmin will be List<IGrouping<int, AdminViewModel>>, as #itectori suggested.
However, I don't think that's what you're looking for. If I understand correctly, ListOfAdmin should contain, well, the admins. If that is the case, simply select the first item of every IGrouping, like this:
ListOfAdmin = (grp2.SelectMany(y => y.ListOfAdmin).Count()) == 0 ? null : grp2.SelectMany(y => y.ListOfAdmin)
.Select(a => new AdminViewModel
{
id = a.id,
name = a.name
})
.GroupBy(f => f.id)
.Select(g => g.First())
.ToList(),
According to the documentation, GrouBy() returns an object of type IEnumerable<IGrouping<TKey,TElement>>.
In your case,
(grp2.SelectMany(y => y.ListOfAdmin).Count()) == 0 ? null : grp2.SelectMany(y => y.ListOfAdmin)
.Select(a => new AdminViewModel
{
id = a.id,
name = a.name
})
.GroupBy(f => f.id)
.ToList()
return an object of type List<IGrouping<int, AdminViewModel>>
In order for your code to work, you just need to change the type of the SubscriptionViewModel.ListOfAdmin attribute.
class SubscriptionViewModel
{
[...]
public List<IGrouping<int, AdminViewModel>> ListOfAdmin { get; set; }
}
Related
I'm working on an Asp.Net Core project and I need to sort my classes Course.cs by their total time.
I have an entity named "Course.cs" which has one-to-many relation with the entity Episode.cs so that each Course.cs has many Episode.cs inside itself.
My Episode.cs is:
public class Episode
{
[Key]
public int EpisodeId { get; set; }
[Required]
public int CourseId { get; set; }
[Display(Name = "عنوان اپیزود")]
[Required(ErrorMessage ="لطفا {0} را وارد کنید")]
[MaxLength(ErrorMessage ="{0} نمیتواند بیش تر از {1}کاراکتر باشد")]
public string EpisodeTitle { get; set; }
public string EpisodeFileName { get; set; }
[Display(Name = "مدت زمان اپیزود")]
[Required(ErrorMessage = "لطفا {0} را وارد کنید")]
public TimeSpan? EpisodeTimeLength { get; set; }
[Display(Name = "رایگان")]
[Required(ErrorMessage = "لطفا {0} را وارد کنید")]
public bool IsFree { get; set; }
public DateTime CreateDate { get; set; }
#region Navigation Properties
[ForeignKey("CourseId")]
public Course.Courses.Course Course { get; set; }
#endregion
}
As you can see above, I have a property named public TimeSpan? EpisodeTimeLength { get; set; } and want to sort my Course.css depending on this property.
I tried this way:
_dbContext.Courses.Include(c => c.Episodes).AsEnumerable().OrderByDescending(c => c.Episodes.Select(t => t.EpisodeTimeLength));
and then tried this way:
_dbContext.Courses.OrderByDescending(t => t.Episodes.Sum(s => s.EpisodeTimeLength ?? TimeSpan.Zero).Ticks));
but they are not compiled!
Would anybody help?
You can do it easily by summing timespans' total milliseconds:
var ordered = courses
.Include(x => x.Episodes)
.ToList()
.OrderByDescending(x => x.Episodes.Sum(e => e.Length?.TotalMilliseconds ?? 0));
Full sample code below:
public class Program
{
static void Main(string[] args)
{
var courses = new Course[]
{
new Course()
{
Name = "Course 1",
Episodes = new List<Episode>()
{
new Episode(){ Length = null },
new Episode(){ Length = TimeSpan.FromSeconds(30) },
}
},
new Course()
{
Name = "Course 2",
Episodes = new List<Episode>()
{
new Episode(){ Length = TimeSpan.FromSeconds(5) },
new Episode(){ Length = TimeSpan.FromSeconds(6) },
new Episode(){ Length = TimeSpan.FromSeconds(6) },
}
},
new Course()
{
Name = "Course 3",
Episodes = new List<Episode>()
{
new Episode(){ Length = TimeSpan.FromSeconds(5) },
new Episode(){ Length = TimeSpan.FromSeconds(6) },
new Episode(){ Length = TimeSpan.FromSeconds(2) },
new Episode(){ Length = TimeSpan.FromSeconds(7) },
}
},
};
var ordered = courses
.Include(x => x.Episodes)
.ToList()
.OrderByDescending(x => x.Episodes.Sum(e => e.Length?.TotalMilliseconds ?? 0));
foreach (var course in ordered) Console.WriteLine(course.Name);
}
}
public class Course
{
public string Name { get; set; }
public IEnumerable<Episode> Episodes { get; set; }
}
public class Episode
{
public TimeSpan? Length { get; set; }
}
I am trying to seed data and none of my mappings seem to be working. I believe I am following the [textbook examples ][1] from documentation but I must be missing something.
My classes
public class HighSchoolRegistrationModel
{
public long Id{ get; set; }
[Required]
public string SchoolName { get; set; }
[Required]
public string Address { get; set; }
[Required]
[EmailAddress]
public string SchoolEmail { get; set; }
public ICollection<CourseModel> CourseModelsOffered { get; set; }
public ICollection<Student> Students { get; set; }
}
public class Student
{
public long StudentId { get; set; }
public string Name { get; set; }
public long HighSchoolRegistrationModelId { get; set; }
public HighSchoolRegistrationModel HighSchoolRegistrationModel { get; set; }
public Grade CurrentGradeLevel { get; set; }
public ICollection<Guardian> Guardians { get; set; }
public ICollection<Result> Results { get; set; }
public ICollection<CourseInstance> Courses { get; set; }
public ICollection<CourseGrade> CourseGrades { get; set; }
public ICollection<ReportCard> ReportCards { get; set; }
}
public class Result
{
public long ResultId{ get; set; }
public long StudentId { get; set; }
public Student Student { get; set; }
public Exam ExamType { get; set; }
public double Score { get; set; }
}
My context class
// HighSchoolContext, my only context
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<HighSchoolRegistrationModel>().HasData(
new HighSchoolRegistrationModel
{
Id = 1,
SchoolName = "Nouveau Blaise Pascal",
Address = "123 Rue du Ciel",
SchoolEmail = "npb#fauxemails.fr"
}
);
modelBuilder.Entity<CourseModel>().HasData(
new CourseModel()
{
Id = 1,
CourseName = "Maths",
GradeLevel = Grade.Fifth,
HighSchoolRegistrationModelId = 1
},
new CourseModel()
{
Id = 2,
CourseName = "Language",
GradeLevel = Grade.Fifth,
HighSchoolRegistrationModelId = 1
}
);
modelBuilder.Entity<Student>().HasData(
new Student()
{
StudentId = 1,
Name = "Camille Foussoulou",
CurrentGradeLevel = Grade.Fifth,
HighSchoolRegistrationModelId = 1
},
new Student()
{
StudentId = 2,
Name = "Lucas Foussoulou",
CurrentGradeLevel = Grade.Fifth,
HighSchoolRegistrationModelId = 1
}
);
modelBuilder.Entity<Guardian>().HasData(
new Guardian()
{
GuardianId = 1,
Name = "Joseph Foussoulou"
},
new Guardian()
{
GuardianId = 2,
Name = "Jeanne Ntoume"
}
);
modelBuilder.Entity<GuardianStudent>().HasData(
new GuardianStudent() { GuardianId = 1, StudentId = 1},
new GuardianStudent() { GuardianId = 1, StudentId = 2},
new GuardianStudent() { GuardianId = 2, StudentId = 1},
new GuardianStudent() { GuardianId = 2, StudentId = 2}
);
modelBuilder.Entity<Result>().HasData(
new Result()
{
ResultId = 1,
StudentId = 1,
ExamType = Exam.Art,
Score = 77.7
},
new Result()
{
ResultId = 2,
StudentId = 1,
ExamType = Exam.Language,
Score = 77.5
}
...//more results
);
modelBuilder.Entity<Instructor>().HasData(
new Instructor() { InstructorId = 1, Name = "Jacques Alassane" },
new Instructor() { InstructorId = 2, Name = "Alice des Plaines" }
);
modelBuilder.Entity<CourseInstance>().HasData(
new CourseInstance()
{
CourseInstanceId = 1,
CourseModelId = 1,
InstructorId = 1,
},
new CourseInstance()
{
CourseInstanceId = 2,
CourseModelId = 2,
InstructorId = 2,
}
);
modelBuilder.Entity<CourseGrade>().HasData(
new CourseGrade()
{
CourseGradeId = 1,
StudentId = 1,
CourseInstanceId = 1,
Grade = 75.3
},
new CourseGrade()
{
CourseGradeId = 2,
StudentId = 1,
CourseInstanceId = 1,
Grade = 72.3
}
//more grades
);
modelBuilder.Entity<CourseInstanceStudent>().HasData(
new CourseInstanceStudent() { CourseInstanceId = 1, StudentId = 1},
new CourseInstanceStudent() { CourseInstanceId = 1, StudentId = 2},
new CourseInstanceStudent() { CourseInstanceId = 2, StudentId = 1},
new CourseInstanceStudent() { CourseInstanceId = 2, StudentId = 2}
);
}
Yet, when run add migration, update database, start up my app and hit api/Students (standard http get in postman), my Students do not have any Results. Nor any of the other entities in the collection that I meant to seed for that matter. What did I miss?
EDIT
To clarify more, my api:
// StudentsController.cs
[HttpGet]
public async Task<ActionResult<IEnumerable<Student>>> GetStudents()
{
return await _context.Students.ToListAsync();
}
Where I call it in the front end
//StudentService.cs
public async Task<IEnumerable<Student>> GetStudentsAsync()
{
var options = new JsonSerializerOptions()
{
ReferenceHandler = ReferenceHandler.Preserve,
PropertyNameCaseInsensitive = true
};
return await http.GetFromJsonAsync<IEnumerable<Student>>("api/Students", options);
}
The response:
{"$id":"1","$values":[{"$id":"2","studentId":1,"name":"Camille Foussoulou","highSchoolRegistrationModelId":1,"highSchoolRegistrationModel":null,"currentGradeLevel":1,"guardians":null,"results":null,"courses":null,"courseGrades":null,"reportCards":null},{"$id":"3","studentId":2,"name":"Lucas Foussoulou","highSchoolRegistrationModelId":1,"highSchoolRegistrationModel":null,"currentGradeLevel":1,"guardians":null,"results":null,"courses":null,"courseGrades":null,"reportCards":null}]}
The commmands I ran
dotnet ef migrations add InitialCreate -c HighSchoolContext
dotnet ef database update -c HighSchoolContext
Using Sqlite at the moment.
[1]: https://learn.microsoft.com/en-us/ef/core/modeling/relationships?tabs=fluent-api%2Cfluent-api-simple-key%2Csimple-key
It turns out that I had simply forgotten to define what related data I wanted included with the entity I was reading from the database. In this example, to get the Results of the Student I just did this
[HttpGet]
public async Task<ActionResult<IEnumerable<Student>>> GetStudents()
{
return await _context.Students
.Include(s => s.Results)
.ToListAsync();
}
Which is eager loading, as I go on I'll probably explore different loading strategies.
I have an entity Contracts, ListKindWorks and KindWorks.
public partial class Contracts
{
public Contracts()
{
ListKindWorks = new HashSet<ListKindWorks>();
}
public int Id { get; set; }
...
public virtual ICollection<ListKindWorks> ListKindWorks { get; set; }
}
public partial class ListKindWorks
{
public int IdContract { get; set; }
public int IdKindWork { get; set; }
public virtual Contracts IdContractNavigation { get; set; }
public virtual KindWorks IdKindWorkNavigation { get; set; }
}
public partial class KindWorks
{
public KindWorks()
{
ListKindWorks = new HashSet<ListKindWorks>();
}
public int Id { get; set; }
public string Title { get; set; }
public virtual ICollection<ListKindWorks> ListKindWorks { get; set; }
}
I want to load related elements. Something like this pseudocode:
source = model.Contracts
.Select(c => new MyType
{
IdContract = c.Id,
KindWork = new List<Item>
{ Id = KindWorks.Id, Value = KindWorks.Title }
// or
// KindWork = c.ListKindWorks
// .Where(x => x.IdContract == c.Id)
// .Select(y => new Item
// { Id = y.IdKindWork, Value = y.IdKindWorkNavigation.Title })
...
})
.ToList();
public class Item
{
public int Id { get; set; }
public string Value { get; set; }
}
Can I load List<Item> for each Contracts?
If I understand what you are looking for, I create a List for each contract in a dictionary. And here is my result:
var contracts = new List<Contracts>
{
new Contracts { Id = 1 },
new Contracts { Id = 2 },
new Contracts { Id = 3 },
};
var listKindWorks = new List<ListKindWorks>
{
new ListKindWorks { IdContract = 1, IdKindWork = 1 },
new ListKindWorks { IdContract = 1, IdKindWork = 2 },
new ListKindWorks { IdContract = 2, IdKindWork = 2 },
new ListKindWorks { IdContract = 2, IdKindWork = 3 }
};
var kindWorks = new List<KindWorks>
{
new KindWorks { Id = 1, Title = "Title 1" },
new KindWorks { Id = 2, Title = "Title 2" },
new KindWorks { Id = 3, Title = "Title 3" },
};
Dictionary<Contracts, List<Item>> myDic = contracts.Select(
contract => contract).ToDictionary(
contract => contract,
contract => listKindWorks.Where(
listKindWork => listKindWork.IdContract.Equals(contract.Id))
.Select(listKindWork => new Item
{
Id = kindWorks.FirstOrDefault(kindWork => kindWork.Id.Equals(listKindWork.IdKindWork))?.Id?? listKindWork.IdKindWork,
Value = kindWorks.FirstOrDefault(kindWork => kindWork.Id.Equals(listKindWork.IdKindWork))?.Title?? "KindWork not found"
}).ToList());
I obtain this for my test :
Contract1 : Title1, Title2
Contract2 : Title2, Title3
Contract3 : Nothing
IEnumerable<Item> KindWork = c.ListKindWorks
.Select(y => new Item
{
Id = y.IdKindWork,
Value = y.IdKindWorkNavigation.Title
})
IEnumerable<Item> Subject = c.ListSubjects
.Select(y => new Item
{
Id = y.IdSubject,
Value = y.IdSubjectNavigation.Title
})
I have a dictionary defined as
var dataDict = new Dictionary<String, List<RICData>>();
with the RICData class defined as
class RICData
{
public string pubdate { get; set; }
public string settle { get; set; }
public int colorder { get; set; }
}
The following illustrates the data the dictionary dataDict contains -
"TEST1", ("12/01/2015, 100.1, 1", "12/02/2015, 200.1, 2", "12/03/2015, 300.4, 3")
"TEST2", ("12/01/2015, 150.1, 6", "12/02/2015, 200.1, 7")
"TEST3", ("12/01/2015, 250.1, 4", "12/02/2015, 400, 5")
What I would like to do is group the data by date and order by colorder and retun something simlar to what is below
"12/01/2015", ("TEST1, 100.1, 1", "TEST3, 250.1, 4", "TEST2, 150.1, 6")
"12/02/2015", ("TEST1, 200.1, 2", "TEST3, 400, 5", "TEST2, 200.1, 7"
"12/03/2015", ("TEST1, 300.4, 3")
Here's some sample code. I guess I'm not sure how to group this data
var dataDict = new Dictionary<String, List<RICData>>();
var rdList = new List<RICData>();
rdList.Add(new RICData{pubdate = "12/01/2015", settle = "100.1", colorder = 1});
rdList.Add(new RICData{pubdate = "12/02/2015", settle = "110.1", colorder = 2});
rdList.Add(new RICData { pubdate = "12/03/2015", settle = "120.1", colorder = 3 });
dataDict.Add("TEST1", rdList);
var rdList1 = new List<RICData>();
rdList1.Add(new RICData { pubdate = "12/01/2015", settle = "140.1", colorder = 6 });
rdList1.Add(new RICData { pubdate = "12/02/2015", settle = "100.1", colorder = 7 });
dataDict.Add("TEST2", rdList1);
var rdList2 = new List<RICData>();
rdList2.Add(new RICData { pubdate = "12/01/2015", settle = "240.1", colorder = 4 });
rdList2.Add(new RICData { pubdate = "12/02/2015", settle = "200.1", colorder = 5 });
dataDict.Add("TEST3", rdList2);
//?????
var resultGrp = dataDict.GroupBy(p => p.Value.Select(x => x.pubdate));
public class RICData
{
public string PubDate { get; set; }
public string Settle { get; set; }
public int ColorDer { get; set; }
}
public class NewRICData
{
public string Label { get; set; }
public string Settle { get; set; }
public int Colorder { get; set; }
}
var oldDict = new Dictionary<string, List<RICData>>();
var newDict = oldDict.SelectMany(pair => pair.Value.Select(data => new
{
PubDate = DateTime.Parse(data.PubDate),
NewRICData = new NewRICData
{
Label = pair.Key,
Settle = data.Settle,
ColorDer = data.ColorDer
}
}))
.GroupBy(x => x.PubDate.Date)
.ToDictionary(group => group.Key.ToString("d"),
group => group.Select(x => x.NewRICData)
.OrderBy(x => x.ColorDer));
Given the classes below, I need to establish the mapping from Person to PersonDTO. The problem I am having is that PersonDTO's address field mapping did not occur.
public class Address
{
public int Id { get; set; }
public string Value { get; set; }
}
public class RegisteredAddresses
{
public int Id { get; set; }
public List<Address> Addresses { get; set; }
public RegisteredAddresses()
{
this.Addresses = new List<Address>();
}
}
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public List<RegisteredAddresses> AddressGroups { get; set; }
public Person()
{
this.AddressGroups = new List<RegisteredAddresses>();
}
}
public class PersonDTO
{
public string Name { get; set; }
public List<Address> Addresses { get; set; }
public PersonDTO()
{
this.Addresses = new List<Address>();
}
}
class Program
{
static void Main(string[] args)
{
RegisteredAddresses registeredAddresses1 = new RegisteredAddresses();
RegisteredAddresses registeredAddresses2 = new RegisteredAddresses();
Person person = new Person();
registeredAddresses1.Addresses.Add(new Address { Id = 1, Value = "address 1" });
registeredAddresses1.Addresses.Add(new Address { Id = 2, Value = "address 2" });
registeredAddresses1.Addresses.Add(new Address { Id = 3, Value = "address 3" });
registeredAddresses1.Addresses.Add(new Address { Id = 4, Value = "address 4" });
registeredAddresses1.Addresses.Add(new Address { Id = 5, Value = "address 5" });
registeredAddresses2.Addresses.Add(new Address { Id = 1, Value = "address A" });
registeredAddresses2.Addresses.Add(new Address { Id = 2, Value = "address B" });
registeredAddresses2.Addresses.Add(new Address { Id = 3, Value = "address C" });
registeredAddresses2.Addresses.Add(new Address { Id = 4, Value = "address D" });
registeredAddresses2.Addresses.Add(new Address { Id = 5, Value = "address E" });
person.Name = "person 1";
person.AddressGroups.Add(registeredAddresses1);
person.AddressGroups.Add(registeredAddresses2);
Mapper.CreateMap<Person, PersonDTO>();
// after this line....
var personDto = Mapper.Map<Person, PersonDTO>(person);
// .... personDTO.Addresses.Count() is zero; where it should be 10
}
}
You need to tell AutoMapper how to map from the addresses contained in the AddressGroups to the addresses in PersonDTO. Something like:
Mapper.CreateMap<Person, PersonDTO>()
.ForMember(pd => pd.Addresses,
opt => opt.ResolveUsing(p => p.AddressGroups
.SelectMany(ra => ra.Addresses)
)
);