NHibernate Parent Child Mapping - nhibernate

I have a parent/child database relationship between the table ACCOUNT and the table USER. Currently I have mapped a bi-directional Fluent mappings like this:
public class Account {
public virtual IList<User> ListUsers { get; private set; }
public virtual void AddUser(User user)
{
user.Account = this;
ListUsers.Add(user);
}
}
MAPPING: HasMany(x => x.ListUsers).Table("UserInfo").KeyColumn("Id_Account").Inverse().Cascade.All().AsList();
public class User {
public virtual Account Account { get; set; }
public string Username { get; set; }
}
MAPPING: References(x => x.Account).Column("Id_Account");
In practice I cannot foresee that I will ever want to reference the Account entity from the User entity. Likewise I cannot foresee my wanting to load all of the User entities from the parent Accounts entity. I am fairly new to NHibernate and was wondering is the above method still the best way to go performance wise? Is a bi-directional relationship preferred and should I look to referencing the Id only? Thanks

bi-directional references is the correct approach, in my opinion. If you use lazy-loading on the Account property, then it would only load the account's id anyway.
you specified that the ListUsers property is inverse=true, meaning the User entity is responsible for saving the reference. Therefore, I believe (if I remember correctly) that the line ListUsers.Add(user); is not necessary, since the association will be created by the User entity.
So this means that you don't have to load the entire ListUsers collection from the db when you add a user.

Related

ASP.NET Core 3.1 Web API: how to protect sensitive data from return with model?

I have a Posts model class that has a relation with Users model.
When I call API to get Posts with the owner of it (user), it returns with all user info including password.
How to prevent model from returning sensitive information like passwords?
You should create new classes that you return from your actions. Only include the fields/information you want to return.
These classes are also known as Data Transfer Objects (DTO).
You can use [JsonIgnore] to avoid serializing the property value:
public class Users
{
public int Id { get; set; }
[System.Text.Json.Serialization.JsonIgnore]
public string Password{ get; set; }
//...
}

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.

Entity Framework Core: using navigation properties without foreign key

I have following object model:
public class SharingRelation:BaseEntity
{
public Guid? Code { get; set; }
public string Value { get; set; }
}
public class SecondLevelShareEntity : BaseEntity
{
public string Name { get; set; }
public Guid? SharingCode { get; set; }
public List<SharingRelation> SharingRelations { get; set; }
}
In my database (it may be poor db design but I need to answer this question for research), SharingRelation is some sort of dependent entity of SecondLevelShareEntity on Code == SharingCode values. I can have two entities of type SecondLevelShareEntity with same SharingCode value. So, for each of them I need to get all related SharingRelation objects depending on Code and SharingCode values. I can do it using SQL and join on this columns. But how can I do it using EF Core and navigation properties (I want to get all dependent entities using Include() for example)? When I configure my entities like this
public class SharingRelationEntityTypeConfiguration : BaseEntityTypeConfiguration<SharingRelation>
{
public override void Configure(EntityTypeBuilder<SharingRelation> builder)
{
base.Configure(builder);
builder.HasOne<SecondLevelShareEntity>().WithMany(x => x.SharingRelations).HasForeignKey(x => x.Code)
.HasPrincipalKey(x => x.SharingCode);
}
}
EF Core creates foreign key and marks it unique. I am obviously getting an error that that is impossible to have several SecondLevelShareEntity with the same SharingCode
System.InvalidOperationException : The instance of entity type 'SecondLevelShareEntity' cannot be tracked because another instance with the key value '{SharingCode: 8a4da9b3-4b8e-4c91-b0e3-e9135adb9c66}' is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached.
How can I avoid creation of foreign key, but keep using navigation properties (as far, as I see normal queries with navigations generate simple JOIN statements)
UPDATED I can provide real data in database. SecondLevelShareEntity table looks like this:
_id Name SharingCode
----------------------------------------------------------------------
1 "firstSecondLevelEnt" "efcb1c96-0ef1-4bb3-a952-4a6511ab448b"
2 "secondSecondLevelEnt" "efcb1c96-0ef1-4bb3-a952-4a6511ab448b"
And SharingRelation table looks like this:
_id Value Code
----------------------------------------------------------------------
1 "firstSharingRelation" "efcb1c96-0ef1-4bb3-a952-4a6511ab448b"
2 "secondSharingRelation" "efcb1c96-0ef1-4bb3-a952-4a6511ab448b"

Loading a base class through nhibernate incorrectly uses mappings from derived classes

I have a scenario where I have a base class as one entity, then another entity that derives from the other base class. Both have meaning in my domain and can be used separately.
public class MyBaseClass
{
int ID { get; set; }
string Name { get; set; }
}
public class MyChildClass
{
string AdditionalField { get; set; }
}
I have both mapped using Fluent nHibernate using ClassMap like this:
public class MyBaseClassMap : ClassMap<MyBaseClass>
{
Id("MyBaseClassID");
Map(x => x.Name);
}
public class MyChildClassMap : SubclassMap<MyChildClass>
{
Map(x => x.AdditionalField);
}
What is happening is when I try to fetch a copy of the base class, its using the mapping for the child class. Its as if it doesn't know the the difference between the base and child class, or its choosing the wrong mapping for it. I confirmed this by watching the SQL statement and its joining to the child table and fetching the additional column. Any way to get it to use the right map?
That's the 'nature' of NHibernate.
The behaviour you're describing, is called 'polymorphic queries'.
Since MyChildClass is a MyBaseClass, the MyChildClass instances are retrieved as well.
If you want to avoid this behaviour, you can maybe have a look at the answers in this topic. (I've never 'disabled' the polymorphic query ability).

NHibernate: Mapping different dynamic components based on a discriminator

My domain entities each have a set of "fixed" properties and a set of "dynamic" properties which can be added at runtime. I handle this by using NHibernate's dynamic-component functionality.
public class Product {
public virtual Guid Id { get; }
public virtual string Name { get; set;}
public virtual IDictionary DynamicComponents { get; }
}
Now I have the following situation
public class Customer {
public virtual Guid Id { get; }
public virtual string Type { get; set;}
public virtual IDictionary DynamicProperties { get; }
}
Where a CustomerType is something like "Online" or "InPerson". Furthermore an Online customer has dynamic properties "Name" and "IPAddress" and an InPerson Customer has dynamic properties "Name" and "Salesman".
Which customer types are available and the extra properties on them are configured in meta-data which is used to generate hbm files on application start.
I could figure out some way to knock this together using an intermediate DTO layer, but is there any support in NHibernate for this scenario? The only difficulty seems to be that all the different "types" of customer map to the same Customer class.
Maybe a stupid question, but why don't you just use two subclasses of Customer?
Other than that it is not immediately clear to me what it is you want NHibernate to support. Can you clarify what "any support in NHibernate for this scenario" means, what do you want NHibernate to do for you?
I think you can find a solution using the dynamic properties... in your subclasses, refer to the dynamic properties such as IPAddress { get { return DynamicProperties["ipAddress"] as IPAddress; } }
Interesting part for me is how do you map these properties in such a way that is scalable...
Did you come up with a different solution?