Using LINQ to combine object and nested collection information into a new object - vb.net

Using LINQ, is it possible to combine properties from both an object and a nested collection of that object into a new object? So for each item in the nested collection, I want to create a new object that has the nested object information coupled with the parent object's info.
Using a sample scenario, I'm trying to do something like this:
Teachers.Select(Function(item) New TeacherRecord() With
{.TeacherId = item.Id,
.TeacherName = item.Name,
.StudentID = ? ,
.StudentName = ?}).ToList()
Sample Classes
Public Property Teachers as List(of Teacher)
Public Class Teacher
Public Property ID as Integer
Public Property Name as String
Public Property Room as String
Public Property Students as List(of Student)
End class
Public Class Student
Public Property ID as Integer
Public Property Name as String
End Class
Public Class TeacherRecord
Public Property TeacherId as Integer
Public Property TeacherName as String
Public Property StudentId as Integer
Public Property StudentName as String
End Class

You need to use SelectMany, I don't know much about VB but this is how you do it in C#:
List<TeacherRecord> records = teachers.SelectMany(t => t.Students, (t, s) =>
new TeacherRecord { TeacherId = t.ID,
TeacherName = t.Name,
StudentId = s.ID,
StudentName = s.Name }).ToList();

you will need to rethink your TeacherRecord relationship to a Teacher Or Student - now it is unclear, but generally you can combine then for your ViewData and code will look like this:
void Main(){
List<Teacher> teacher = new List<Teacher>();
List<Student> student = new List<Student>();
student.Add(new Student{ID=1,Name="Tom"});
student.Add(new Student{ID=2,Name="Jerry"});
teacher.Add(new Teacher{ID=1
,Name="John"
,Room = "Room A"
,Students = student});
var combined = (from t in teacher
select t).ToList();
}
// Define other methods and classes here
public class Teacher
{
public int ID { get; set; }
public string Name { get; set; }
public string Room { get; set; }
public List<Student> Students { get; set; }
}
public class Student
{
public int ID { get; set; }
public string Name { get; set; }
}
public class TeacherRecord
{
public int TeacherId { get; set; }
public string TeacherName { get; set; }
public int StudentId { get; set; }
public string StudentName { get; set; }
}
and result will be something like this:

Related

child relationship not available in parent object

I have the following method that returns a list of factory cars.
It works, but the ordering is wrong.
CarEngines can have an orderId and I want to order by that.
Looking at other answers on here, I see that you can't do an order by inside the query and you have to do it afterwards.
The problem is, I can't access CarEngines as you can see below:
public async Task<ActionResult<CountryList>> GetCountryCarObject(Guid countryID)
{
var factoryCars = await _context.CountryList
.Include(n => n.CarList).ThenInclude(l => l.CarEngines)
.Include(n => n.CarList).ThenInclude(l => l.CarOptions)
.SingleOrDefaultAsync(c => c.CountryId == countryID);
factoryCars.CarList.CarEngines <== CarEngines doesn't show up in CarList object
return factoryCars;
}
It is telling me that CarList doesn't contain a definition for CarEngines.
But it is in my CarList model, I have it defined like so:
public CarList()
{
CarEngines = new HashSet<CarEngines>();
}
public virtual ICollection<CarEngines> CarEngines { get; set; }
Here are the two models:
public partial class CarList
{
public CarList()
{
CarEngines = new HashSet<CarEngines>();
CarOptions = new HashSet<CarOptions>();
}
public string CarId { get; set; }
public string CarMake { get; set; }
public string CarModel { get; set; }
public Guid? CarCountryId { get; set; }
public virtual ICollection<CarEngines> CarEngines { get; set; }
public ICollection<CarOptions> CarOptions { get; set; }
}
public partial class CountryList
{
public CountryList()
{
CarList = new HashSet<CarList>();
}
[Key]
public Guid CountryId { get; set; }
public string CountryName { get; set; }
public string CountryLocation { get; set; }
public string CountryDesc { get; set; }
public virtual ICollection<CarList> CarList { get; set; }
}
So I'm not sure it doesn't see it.
Is there a way to get this to work?
Thanks!
Ok so the fact that there is something called CarList but is not a List is super confusing but moving on....
The issue is that CarList is a List. So use something like factoryCars.CarList.Select( x=>x.CarEngines). Also rename that to var country instead of var factoryCars since you return a single country and not a list of cars.
Also rename your variables and classes this confusion was probably caused by this. For example instead of having ICollection<CarList> CarList you can rename it into ICollection<Car> Cars so right now from the name you can easilly understand there are multiple cars (thus its a collection) which includes the object Car

Get Value from other Table by ID with Entity Framework

i have two already existings tables (no foreignkey):
Customer (Id, Name, .....)
Projects (Id, CustomerId, name)
And in my asp.net core application i have two model:
public class Customer {
public int Id { get; set; };
public String Name { get; set; };
}
public class Project {
public int Id { get; set; };
public Customer Customer{ get; set; };
public String Name{ get; set; };
}
And the datacontext classes for this
public class CustomerContext: DbContext
{
public CustomerContext(DbContextOptions<CustomerContext> options) : base(options)
{
}
public DbSet<CustomerContext> Customer { get; set; }
}
public class ProjectContext: DbContext
{
public ProjectContext(DbContextOptions<ProjectContext> options) : base(options)
{
}
public DbSet<ProjectContext> Project{ get; set; }
}
But i cant find out how to fetch the Customer object in the Projectclass by the customerId
Can someone help me please? Thank you
Edit: Now i change my Model Classes like in the answer below
but with the following i get an SQL Exception while loading the page
SqlException: Invalid object name 'Customer'.
projectList = await (from project in _context.Project
join customer in _customerContext.Customer on project.CustomerId equals customer.Id into tmp
from m in tmp.DefaultIfEmpty()
select new Project
{
Id = sollIst.Id,
CustomerId = sollIst.CustomerId,
Customer = m,
Name = sollIst.Name,
}
).ToListAsync();
Update your model classes as below:
public class Customer {
public int Id { get; set; };
public String Name { get; set; };
}
public class Project {
public int Id { get; set; };
public String Name{ get; set; };
public int CustomerID { get; set; }
[ForeignKey("CustomerID")]
public Customer Customer{ get; set; };
}
Merger both DbContext into one.
public class ProjectContext: DbContext
{
public ProjectContext(DbContextOptions<ProjectContext> options) : base(options)
{
}
public DbSet<Project> Projects { get; set; }
public DbSet<Customer> Customers { get; set; }
}
Then execute
projectList = await (from project in _context.Project
join customer in _context.Customer on project.CustomerId equals customer.Id into tmp
from m in tmp.DefaultIfEmpty()
select new Project
{
Id = sollIst.Id,
CustomerId = sollIst.CustomerId,
Customer = m,
Name = sollIst.Name,
}
).ToListAsync();
I hope following links will help you to know how to join two tables across different database.
Joining tables from two databases using entity framework.
Entity framework join across two databases
You will have to create a property in Project class that represent the "foreign key".
Lets say in Project table in the database the "foreign key" is CustomerID, add this to Project class:
public int CustomerID { get; set; }
Then add the ForeignKey attribute to the Customer property:
[ForeignKey("CustomerID")]
public Customer Customer { get; set; }
First, your model classes should be as follows:
public class Customer {
public int Id { get; set; };
public string Name { get; set; };
}
public class Project {
public int Id { get; set; };
[ForeignKey("Customer")]
public int CustomerId{ get; set; };
public string Name{ get; set; };
public Customer Customer { get; set; };
}
Then your DbContext classes should be as follows:
public class CustomerContext: DbContext
{
public CustomerContext(DbContextOptions<CustomerContext> options) : base(options)
{
}
public DbSet<Customer> Customers { get; set; }
}
public class ProjectContext: DbContext
{
public ProjectContext(DbContextOptions<ProjectContext> options) : base(options)
{
}
public DbSet<Project> Projects { get; set; }
}
Now you can use Entity Framework Core and LINQ query to fetch your desired data.

How to add where clause for child items in Castle ActiveRecord

I am using Castle ActiveRecord and created two entities as follow :
[ActiveRecord("Teams")]
public class Team : ActiveRecordLinqBase<Team>
{
public Team()
{
Members = new List<Member>();
}
[PrimaryKey]
public int Id { get; set; }
[Property("TeamName")]
public string Name { get; set; }
[Property]
public string Description { get; set; }
[HasMany(Inverse = true,
Lazy = true,
Cascade = ManyRelationCascadeEnum.AllDeleteOrphan)]
public virtual IList<Member> Members { get; set; }
}
[ActiveRecord("Members")]
public class Member : ActiveRecordLinqBase<Member>
{
[PrimaryKey]
public int Id { get; set; }
[Property]
public string FirstName { get; set; }
[Property]
public string Lastname { get; set; }
[Property]
public string Address { get; set; }
[BelongsTo("TeamId")]
public Team Team { get; set; }
}
And I used ICriterion to have filtered Team data
IList<ICriterion> where = new List<ICriterion>();
where.Add(Expression.Eq("Name", "name1"));
ICriterion[] criteria = where.ToArray();
var teams = Team.FindAll(criteria);
So far it works well, but I want to add another filter on Members table. The result query would be like this
select *
from Teams t join Member m on t.Id = m.TeamId
where t.Name = 'name1'
and m.Address = 'address'
How to get this done using ICriterion?
I mean how to add criterion for Team.Members property.
Not using LINQ. (I know this could be done using linq easily)
For join you can use
DetachedCriteria
DetachedCriteria criteriaTeam = DetachedCriteria.For<Team>();
DetachedCriteria criteriaMember = criteriaTeam .CreateCriteria("Members");
criteriaTeam .Add(Expression.Eq("Name", "name1"));
criteriaMember.Add(Expression.Eq("Address", "address"));
ICriteria executableCriteria = criteriaTeam .GetExecutableCriteria(session);
executableCriteria.List<Team>();
This will return only Team.To return both Team and Members in a single fetch you can use NHibernate result transformer Projections in NHibernate

Sorting with Mathematical Formula with nHibernate (C#)

public class Feedback
{
public virtual int Id { get; private set; }
public virtual string ContentText { get; set; }
public virtual DateTime FeedbackDate { get; set; }
public virtual Student student { get; set; }
}
My Feedback Class.
public class Student
{
public virtual int Id { get; private set; }
public virtual int NumberOfStars { get; set; }
public virtual IList<Feedback> Feedbacks { get; private set; }
public Student()
{
Feedback = new List<Feedbacks>();
}
}
My Student Class
public class Course
{
public virtual int Id { get; set; }
// bla bla bla
public virtual IList<Student> Students { get; private set; }
public Course()
{
Students = new List<Student>();
}
public IList<Student> SortBy(string type)
{
// some other sorting
else if (type.Equals("popular")){
sortedStudents = session.CreateCriteria(typeof(Student))
.CreateAlias("Student", "s")
.CreateAlias("s.Feedback", "f")
.AddOrder(Order.Desc( -------- ))
.List();
}
return (IList<Student>) sortedStudents;
}
}
My Course class
I want sort students in a Course with method SortBy :
if type is x i will sort with following rule
(Students.Feedback.Count)*5 + Student.NumberOfStars)
How ?
HQL:
List<Student> sortedStudents = session
.CreateQuery(
#"from Students student
where student.Course == :course
order by size(student.Feedbacks) * 3 + student.NumberOfStars")
.SetEntity("course", course)
.List<Student>();
size is a HQL function. See the chapter "Expressions" in the NH documentation.
You may also select it with Criteria and sort it with Linq.
Edit
Just saw that you use it in a property and you may have the students already in memory.
You don't need a query, just to sort it.
return students
.OrderBy(x => x.Feedback.Count * 5 + x.NumberOfStars)
.ToList();
Query with LINQ
IList sortedStudents = (from student in this.Students
where student.Course == this
orderby (student.Feedbacks.Count*3 + student.NumberOfStars)
select student).ToList();

Using fluent-nhibernate is it possible to automap a Value Object(s) inside an Entity?

I'm using Sharp Architecture and have a number of situations where Value Objects are used in an Entity. Here is an obvious simple example:
public class Person : Entity
{
protected Person(){}
public Person(string personName)
{
this.PersonName = personName;
}
public virtual string PersonName { get; protected set;}
public virtual StreetAddress MailingAddress { get; set; }
}
public class StreetAddress : ValueObject
{
protected StreetAddress(){}
public StreetAddress(string address1, string address2, string city, string state, string postalCode, string country )
{
this.Address1 = address1;
this.Address2 = address2;
this.City = city;
this.State = state;
this.PostalCode = postalCode;
this.Country = country;
}
public virtual string Address1 { get; protected set; }
public virtual string Address2 { get; protected set; }
public virtual string City { get; protected set; }
public virtual string State { get; protected set; }
public virtual string PostalCode { get; protected set; }
public virtual string Country { get; protected set; }
}
This of course throws: An association from the table Person refers to an unmapped class: Project.Domain.StreetAddress
because the the AutoPersistenceModelGenerator only includes classes with type IEntityWithTypedId<>. Its not clear how Sharp Architecture expects this common condition to be implemented. Does this have to be handled with a bazillion overrides?
You could change the GetSetup() method in AutoPersistenceModelGenerator to something like:
private Action<AutoMappingExpressions> GetSetup()
{
return c =>
{
c.IsComponentType = type => type.BaseType == typeof (ValueObject);
};
}
I'll try to get the blogpost I saw covering this posted for credit.
You would want to map this as a component. You can use the mapping overrides in Fluent NHibernate to accomplish this.
I agree with Alec. I would map this as a component.
For more information on that, see this SO question:
AutoMapping a Composite Element in Fluent Nhibernate
There, you'll also find info on how to map a collection of composite elements.