Sorting with Mathematical Formula with nHibernate (C#) - nhibernate

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();

Related

How can i get my related object from database?

I have 2 classes:
public class Category
{
public int Id { get; set; }
[Required(ErrorMessage = "Pole nie może być puste")]
public string Name { get; set; }
public List<Subcategory> Subcategories {get;set;}
}
public class Subcategory
{
public int Id { get; set; }
[Required(ErrorMessage = "Pole nie może być puste")]
[DisplayName("Nazwa podkategorii")]
public string Name { get; set; }
public int CategoryId { get; set; }
public Category Category { get; set; }
}
And I have got class where I am trying get my object "Category"
public IEnumerable<Category> GetAllCategories()
{
return context.Categories.Include(c => c.Subcategories);
}
public Category GetCategory(int Id)
{
return context.Categories.Find(Id);
}
Method GetAllCategories works fine, but when I use GetCategory I get only Category data without related object "Subcategory" list. Someone can help me with my problem? How can I get whole object?
You need to include relations that you need:
public Category GetCategory(int Id)
{
return context.Categories.Include(e => e.Subcategories).Single(e => e.Id == Id);
}
You can see more examples here: https://learn.microsoft.com/en-us/ef/core/querying/related-data

Querying a table that relates to multiple entity types

So currently I have an application model of:
Note -> Thing
(A note can relate to many things)
A thing can be numerous entities (for this example lets use Computer & Car)
e.g
Note -> Computer
-> Car
So right now, I have the schema of
Note -> ComputerNote -> Computer
Note -> CarNote -> Car
The problem is that because the entity links are in separate tables, it requires a new query to be written rather than just using filtering in the WHERE clause.
Ideally it would be nice to have an EntityId & EntityTypeId column & on the Note table that would hold the primary key of the related entity and the type of the entity. Thus application logic could look for all Car notes where the car is x without a separate query for each type, but.. this would mean I lose referential integrity. Is there a better way, or is what I have suggested an acceptable design?
Entity Framework Model's:
public partial class Note
{
public Note()
{
NoteComputer = new HashSet<NoteComputer>();
NoteCar = new HashSet<NoteCar>();
NoteThing = new HashSet<NoteThing>();
}
public int Id { get; set; }
public string Value { get; set; }
public string CreatedByUserId { get; set; }
public DateTime CreatedDateTime { get; set; }
public ICollection<NoteComputer> NoteComputer { get; set; }
public ICollection<NoteCar> NoteCar { get; set; }
public ICollection<NoteThing> NoteThing { get; set; }
}
public partial class NoteCar
{
public int Id { get; set; }
public int NoteId { get; set; }
public int CarId { get; set; }
public Car Car { get; set; }
public Note Note { get; set; }
}
public partial class NoteComputer
{
public int Id { get; set; }
public int NoteId { get; set; }
public int ComputerId { get; set; }
public Computer Computer { get; set; }
public Note Note { get; set; }
}
public partial class NoteThing
{
public int Id { get; set; }
public int NoteId { get; set; }
public int ThingId { get; set; }
public Thing Thing { get; set; }
public Note Note { get; set; }
}
As there seems to be no nice way to handle this at the database level, I've found it best to handle this at the application level using the concrete type database schema, to produce dynamic joins.
Example in Entity Framework Core:
public GenericEntityProvider
{
private readonly IEnumerable<IEntityProvider> _entityProviders;
private readonly DatabaseContext _context;
public GenericEntityProvider(IEnumerable<IEntityProvider> entityProviders, DatabaseContext context)
{
_entityProviders = entityProviders;
_context = context;
}
public IEnumerable<Note> Get(Type type, int id) {
var provider = _entityProviders.GetPredicate(type, id);
return _context.Notes.Where(provider);
}
}
public CarNoteProvider : IEntityProvider
{
public Expression<Func<Note, bool>> GetPredicate(Type type, int id)
{
return x => x.CarNote.Any(cn => cn.CarId == id);
}
}

NHibernate Query w/ criteria against collection items

I have the following configuration in the database.
Database Schema
I want to be able to query all the Individuals where they are either an employee or vendor. Of the examples I've seen I can't get any of them to work. The code doesn't throw an error, it just doesn't bring back any records.
Here are the DTO's
public class Individual
{
public virtual int Sid { get; set;}
public virtual string Id { get; set; }
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
public virtual string MiddleInitial { get; set; }
public virtual ISet<Company> Companies { get; set; }
}
public class Company
{
private bool _inactive;
public virtual int Sid { get; set; }
public virtual string Name { get; set; }
public virtual IList<Individual> Individuals { get; set; }
public virtual bool Active
{
get { return !_inactive; }
set { _inactive = value; }
}
public virtual bool IsVendor { get; set; }
}
public class IndividualCompany
{
public virtual Individual Individual { get; set; }
public virtual Company Company { get; set; }
public override bool Equals(object obj)
{
if (obj == null)
return false;
IndividualCompany key = obj as IndividualCompany;
if (key == null)
return false;
if (Individual.Sid == key.Individual.Sid && Company.Sid == key.Company.Sid)
return true;
return false;
}
public override int GetHashCode()
{
int hash = 13;
hash = 7 * hash * Individual.Sid.GetHashCode();
hash = 7 * hash * Company.Sid.GetHashCode();
return hash;
}
}
I have another function that uses these 3 tables and all my Individuals and the collection of Companies gets populated just fine so I know the mapping is working. I just don't know how to add criteria on the child record.
string sql = "from Individual i" +
" inner join fetch i.Companies";
return _session.CreateQuery(sql).List<Individual>();
Here's the query I'd like it to produce.
select i.*
from individual i inner join individual_company_assoc ica
on i.individual_sid = ica.individual_sid
inner join company c
on ica.company_sid = c.company_sid
where c.is_vendor = 0
Here's what I've tried:
public IList<Individual> Get(bool vendorsOnly)
{
try
{
return _session.CreateCriteria<Individual>()
.CreateAlias("Company", "c")
.Add(Restrictions.Eq("c.IsVendor", vendorsOnly))
.List<Individual>();
}
catch (NHibernate.HibernateException)
{
throw;
}
}
I'm not using FluentNHibernate. Any help would be greatly appreciated.
An nHibernate query will not automatically join with other tables, even if you reference columns of a joining table in the query.
You must explicitly state that the query should join with the Company table.
Here's an example which will work. It uses the QueryOver syntax, which is a type-safe wrapper around the Criteria API.
return _session
.QueryOver<Individual>()
.JoinQueryOver<Company>(i => i.Companies>())
.Where(c => c.IsVendor == vendorsOnly)
.TransformUsing(NHibernate.Transform.Transformers.DistinctRootEntity)
.List();

castle activerecord lazy get id

I have these two classes
[ActiveRecord("Customers", Lazy=true)]
public class Customer : ActiveRecordBase<Customer>
{
[PrimaryKey(PrimaryKeyType.Identity, Access = PropertyAccess.AutomaticProperty)]
public virtual int Id { get; private set; }
[Property]
public virtual string Name { get; set; }
[HasMany(Lazy = true)]
public virtual IList<Order> Orders { get; set; }
}
[ActiveRecord("Orders", Lazy=true)]
public class Order : ActiveRecordBase<Order>
{
[PrimaryKey(PrimaryKeyType.Identity, Access = PropertyAccess.AutomaticProperty)]
public virtual int Id { get; private set; }
[Property]
public virtual string Product { get; set; }
[BelongsTo(Lazy = FetchWhen.OnInvoke)]
public virtual Customer Customer { get; set; }
}
I want to select all orders and foreach of them, get the id of the customer.
So I do this:
using (new SessionScope())
{
var orders = Order.FindAll();
foreach (var o in orders)
{
int id = o.Customer.Id;
}
}
It works, but it creates a SELECT phrase for each call to o.Customer.Id.
Now, the Order already has the Id of the customer, so how can I get it without revisiting the database??
the following code should allow you to get the id (but I couldn't test it at the moment):
int id = (int)((INHibernateProxy)order.Customer).HibernateLazyInitializer.Identifier;
Greetings
Juy Juka

NHibernate Relationships in Oracle

After countless hours of trying to make Entity Framework work with Oracle, I have given up and started down the path of NHibernate.
I am struggling with the lingo a bit, and have a question. Given the following classes, how do I make NHibernate (Fluent Mappings) output something similar to the SQL below using the WriteOffApprovalUser.UserName as the key to the Employee.MailID field.
C# Classes
public class WriteOffApprovalUser : EntityBase<WriteOffApprovalUser>
{
public virtual string UserName { get; set; }
public virtual Employee.Employee Employee { get; set; }
}
public class Employee : EntityBase<Employee>
{
public virtual string EmployeeID { get; set; }
public virtual string EmployeeStatusCode { get; set; }
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
public virtual string PreferredName { get; set; }
public virtual string JobTitle { get; set; }
public virtual string Division { get; set; }
public virtual string Department { get; set; }
public virtual string Location { get; set; }
public virtual string City { get; set; }
public virtual string DeskLocation { get; set; }
public virtual string MailID { get; set; }
public virtual string Phone { get; set; }
public virtual string Fax { get; set; }
public virtual string SecCode { get; set; }
public virtual string SupervisorID { get; set; }
}
SQL
SELECT c.user_name,
a.LAST_NAME
|| ', '
|| DECODE (a.PREFERRED_NAME, ' ', a.FIRST_NAME, a.preferred_name)
writeoff_approval_name
FROM writeoff_approval_user c, adp_employee a
WHERE c.USER_NAME = a.USER_ID AND c.exp_date IS NULL
ORDER BY 2
In NHibernate all is about mapping the right way. If you're using fluent you should have defined a reference in WriteOffApprovalUser to an Employee entity. Like in this basic tutorial
public class WriteOffApprovalUserMap : ClassMap<WriteOffApprovalUser>
{
public WriteOffApprovalUserMap()
{
Id(x => x.UserName);
References(x => x.Employee);
}
}
Then all you need to do is a simple query like
List<Employee> employees = session.Where(e => e.exp_date == null);
I haven't seen mapped any Date but I this easy to fix.
Then to have the DECODE feature I will suggest you to do some DDD so instead of simply doing an anemic class for Employee create a property that returns the composed user name.
class Employee
{
public string ComposedName
{
get {
return this.LastName + string.IsNullOrEmpty(this.preferedName) ?
this.FirstName : this.PreferedName;
}
}
}
To me that should be treat as a calculation and there is no need to do it in the SQL query. As a bonus this code can be Unit tested.