nHibernate- a Collection which would contain only a supertype - nhibernate

I have the following classes:
class Employee
{
public string Name { get; set; }
}
class HistoricalEmployee : Employee
{
public DateTime TerminationDate { get; set; }
}
class Company
{
public IList<Person> CurrentEmployees { get; set; }
}
Employee and HistoricalEmployee are mapped using table-per-class-heirarchy strategy.
When I retrieve the CurrentEmployees collection, I want it only to contain elements that are Employee, and NOT HistoricalEmployees.
when an employee 'dies', they're not really deleted, but they become HistoricalEmployee (with a few more attributes, such as termination date etc.).
Obviously, over time, the number of HistoricalEmployees will exceed the number of Employees by magnitudes, so I can't fetch all HistoricalEmployees when I only need current Employees.
How can I (fluently) configure the collection to only retrieve elements of the super class?
I think it's something to do with the Polymorphism property, but I couldn't really figure out how to do that.
thanks,
Jhonny

Ok, I did this like so:
mapping.HasMany(x => x.CurrentEmployees)
//.Where(pqa => pqa.TimeOut != null)
.Where("TerminationDate is null")
apparently, the .Where() function creates a filter on the property, which is exactly what I needed.
notice that I used the string version, and commented-out the Func<> version.
This is because that currently (FNH 1.1), as far as I could determine, the Func<> version doesn't work.
hopes this helps somebody,
J

Related

FluentAssertions GraphComparison, all properties of only output object should be filled

Often in my team people forget to map certain fields from an input object to an output object. I wanted to write a library for unit testing, that checks if all properties on an output object have been filled with a value different than the default value, if not, an exception should be thrown. Ofcourse certain properties will need to be able to be excluded.
I noticed that Fluent Assertions can already do this with the .Should().BeEquivalentTo() Graph comparison.
However, I when a property is not present on the input object, I run into some trouble. Given the following objects:
public class Input
{
public int Age{ get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class Output
{
public int Age { get; set; }
public string FullName{ get; set; }
public static Output CreateFrom(Input i)
{
return new Output
{
Age = i.Age,
FullName= $"{i.FirstName} {i.LastName}"
};
}
}
When I do the following assertion:
var input = new Input
{
Age = 33,
FirstName = "Foo",
LastName = "Bar"
};
var output = Output.CreateFrom(input);
var fullName = $"{input.FirstName} {input.LastName}";
input.Should().BeEquivalentTo(output,
o => o.Using<string>(i => i.Subject.Should().Be(fullName)).When(
info => info.Path.Contains(nameof(output.FullName)))
);
I get an exception that FullName is not a property on the Input object, which is fair, but I can't use .Excluding(o => o.FullName) in this case because that would skip assertion all togheter.
I could use .Excluding(o => o.FullName), and write a seperate assertion below it as follows:
output.FullName.Should().Be(fullName);
but that doesn't fix the problem I'm trying to solve, I want every property to be mapped, OR have a specific assertion in BeEquivalentTo so people don't forget to write mappings. And they can still forget to write this seperate assertion when they add .Exluding.
The .WithMapping<Input>() extension method will also not work, since you can assign one property on the input, to another property on the output, but doesn't account for the scenario described above.
IS there a way to do this with Fluent Assertions? That would be my preference since it's already included in the project. Are there anylibraries that tackle this specific scenario, or am I going to have to write this myself?
Thanks!

Does including Collections in Entities violate what an entity is supposed to be?

I am building a Web API using Dapper for .NET Core and trying to adhere to Clean Architecture principles. The API is consumed by an external Angular front-end.
I have repositories that use Dapper to retrieve data from the database, and this data then passes through a service to be mapped into a DTO for display to the user.
It is my understanding that an entity should be an exact representation of the database object, with no extra properties, and that I should use DTOs if I require some additional properties to show the user (or if I wish to obscure certain properties from the user too).
Suppose I have a DTO:
public class StudentDTO
{
public Guid Id { get; set; }
public string Name { get; set; }
public List<Assignment> Assignments { get; set;}
}
and its corresponding Entity:
public class Student
{
public Guid Id { get; set; }
public string Name { get; set; }
}
With this model, should I want to get a student with all of their assignments, I'd need to have two repository calls, and do something like this in the service:
public StudentDTO GetById(Guid id)
{
var student = this.studentRepository.GetById(id);
var assignments = this.assignmentRepository.GetByStudentId(id);
return SomeMapperClass.Map(student, assignments);
}
But this seems inefficient and unnecessary. My question is, should I not just retrieve the Assignments when I get the student entity in the repository, using a JOIN? Or would this violate what an entity is supposed to be?
I apologise, I do realise this is a rather simple question, but I'd really like to know which method is the best approach, or if they both have their use cases
I think it would be more efficient, since map uses reflections, that is slower tens times
public StudentDTO GetById(Guid id)
{
var student = this.studentRepository.GetById(id);
student.Assignments = this.assignmentRepository.GetByStudentId(id);
return student;
}
but the common way is
return _context.Students.Include(i=>i.Assignments).FirstOrDefault(i=> i.Id==id);
This is why the generic repository is a bad idea in the most casses, since it is hard to guess what set of data you will need.

NHibernate JoinAlias on collection multiple times

I'm using NHibernate 3.33 and QueryOver with Postgre 9.2.
I've got two entities:
public class User {
public virtual string Name { get; set; }
public virtual IList<Reports> Reports { get; set; }
}
and
public class Report {
public virtual string Type { get; set; }
public virtual DateTime ReportDate { get; set; }
public virtual User Author { get; set; }
}
with association - one-to-many (I didn't append additional fields to entities like Id or Name to snippets above). Some report's types are avaliable - month, day.
My goal is to get summary for user - find out whether user has day-report and month-report for current day.
Note: month-report's ReportDate looks like first day of month. Also I want to get it as one row (if it was an SQL) to transform to dto:
public class UserSummaryDto {
public bool HasDayReport { get; set; }
public bool HasMonthReport { get; set; }
}
To achieve my goal I've tried following:
Report dayReport = null;
Report monthReport = null;
var currentDay; // some value of current day
var firstDay; // some value of first day of month
var report = session.QueryOver<User>
.Left.JoinAlias(u => u.Reports, () => dayReport, r => r.ReportDate == currentDay)
.Left.JoinAlias(u => u.Reports, () => monthReport, r => r.ReportDate == firstDat)
.SelectList(
// some logic to check whether user has reports
.TransformUsing(Transformers.AliasToBean<UserSummaryDto>())
.List<UserSummaryDto>()
And I've got error:
'duplicate association path:Reports'.
Is it possible to avoid this problem or it's a limitation of HNibernate?
To answer your question:
...Is it possible to avoid this problem or it's a limitation of HNibernate?
Have to say NO.
For more information see similar Q & A: Rename NHibernate criteria
We are not querying the DB, not using SQL (which does allow to do a lot). Here we work with "mapped" domain model, and that could bring some limitations - as the one discussed here...
If that could help, the workaround is to map such property twice and use the WHERE clause: 6.2. Mapping a Collection
where="" (optional) specify an arbitrary SQL WHERE condition to be used when retrieving or removing the collection (useful if the collection should contain only a subset of the available data)

association, aggregation and composition example

association, aggregation and composition
I want to get the illustration for above three with simple classes. I read a lot from internet. The conclusion is as-
In aggregation people say-
"Class A contains collection of another Class (say B) and if A is destroyed it will not affect its child that is collection will not be destroyed."
How is it possible if one object is destroyed but its property can still exist or what they mean by this.(Am I misinterpreting something)
Class A
{
List<B> lst;
}
Class B
{
}
Consider the following classes,
class Student
{
public string Id { get; set; }
public string Name { get; set; }
}
class Department
{
public IList<Student> Students { get; set; }
public void AddStudent(Student student)
{
//...
}
public void RemoveStudent(Student student)
{
//...
}
}
If you want to add a student to the department, then you call AddStudent() and pass the reference of the Student class instance (note that a reference is passed). So when the department instance is destroyed (set to null for example), then the Students property of that Department instance is no longer available, but the Student instances that have been used to populate this list remain are not destroyed. Hence, the property, in this case a Student instance can still exist.
More information
implementation of composition and aggregation in C#?
C# Tutorial - Aggregation and Composition
Difference between Composition and Aggregation

How to auto-load details (with conditions) associated with an entity using Ria Services?

I'm developing a project using Silverlight 4 and Entity Framework 4 and I'm trying to auto-load the details (with conditions) associated with an entity when the client loads the EntityQuery.
So far, I've been able to put in place a solution, using the Include attribute, that returns all the details associated with the master entity. What I'm missing here is to be able to filter out the details based on some criteria.
As an example, here's what my entities look like:
Entity Movie
Id (int)
[Include]
MovieLocalizedInformations (EntityCollection<MovieLocalizedInformation>)
Entity MovieLocalizedInformation
Id (int)
Movie_Id (int)
LanguageCode (eg.: en)
Title
On my DomainService object, I expose the following method:
public IQueryable<Movie> GetMovies( string languageCode )
{
return this.ObjectContext.Movies.Include( "MovieLocalizedInformations" );
}
This works fine. But when I try to add where clause to filter out the localized information based on the language code, only the movies get loaded on the client.
Is there a way to achieve the filtering in one query?
Note: I'm also using the DomainDataSource with paging on the client so the solution needs to work with that.
Any help would be greatly appreciated!
Thanks,
Jacques.
Not sure about Enitity Framework but with a LinqToSqlDomainService you use the LoadWith loadOption
to include the details entities and then use the AssociateWith LoadOption to filter the detail e.g
DataLoadOptions options = new DataLoadOptions();
options.LoadWith<Movies>(i => i.MovieLocalizedInformations);
options.AssociateWith<Movies>(i => i.MovieLocalizedInformations.Where(d=> myListOfIds.Contains(d.LocationId)));
Ok,
For efficiency reason, I decided to go with custom DTO object that fetches the localized information and flatten the result.
But, the same problem occurred when my custom DTO needed to reference another custom localized DTO.
Here is how I came to do the same as the .Include( "PropertyName" ) that the ObjectSet offers:
Entity LocalizedMovieCollection
public class LocalizedMovieCollection
{
[Key]
public int Id { get; set; }
public string Name { get; set; } (the result of a sub query based on the language)
[Include]
[Association( "LocalizedMovieCollection_LocalizedMovies", "Id", "MovieCollection_Id" )]
public IEnumerable<LocalizedMovie> Movies { get; set; }
}
Entity LocalizedMovie
public class LocalizedMovie
{
[Key]
public int Id { get; set; }
public string Name { get; set; } (the result of a sub query based on the language)
public int MovieCollection_Id { get; set; }
[Include]
[Association( "LocalizedMovie_LocalizedMovieCollection", "MovieCollection_Id", "Id", IsForeignKey = true]
public LocalizedMovieCollection MovieCollection { get; set; }
}
Then, I've declared two methods: One that returns an IQueryable of LocalizedMovieCollection and the other, an IQueryable of LocalizedMovie. (Note: There must be at least one method that returns each type of entity for the entity to get auto-generated on the Silverlight client)
My goal is to automatically load the MovieCollection associated with a Movie so the method definition to get the movies is as follow:
public IQueryable<LocalizedMovie> GetMovies( string languageCode )
{
return from movie in this.ObjectContext.Movies
join movieLocalizedInfo in this.ObjectContext.MovieLocalizedInformations
on movie equals movieLocalizedInfo.Movie
join movieCollection in this.ObjectContext.MovieCollections
on movie.MovieCollection equals movieCollection
join movieCollectionLocalizedInfo in this.ObjectContext.MovieCollectionLocalizedInformations
on movieCollection equals movieCollectionLocalizedInfo.MovieCollection
where movieLocalizedInfo.LanguageCode == languageCode && movieCollectionLocalizedInfo.LanguageCode == languageCode
select new LocalizedMovie()
{
Id = movie.Id,
Name = movieLocalizedInfo.Name
MovieCollection_Id = movieCollection.Id,
MovieCollection = new LocalizedMovieCollection(){ Id = movieCollection.Id, Name = movieCollectionLocalizedInfo.Name }
}
}
When the Silverlight client loads the query, all the LocalizedMovies and their associated LocalizedMovieCollections will be loaded into the context.