Mapping two foreign keys to one primary key (XML Mapping) - nhibernate

I've searched a lot after a solution for this, but the only thing that came out was a solution with FH-mapping instead of XML-mappng.
I'm working with a QR-scanning system where two users can scan eachother. If one user shoots an other user their id got filled in in this table.
So the two FK's will be unique together. 1-2. 2-1, 1-3
So my domain actually contains this two classes:
public class SnappedUsers
{
public virtual User Shooter {get; set;}
public virtual User Target { get; set; }
public virtual DateTime SnapDate { get; set; }
}
public class User : Entity
{
public virtual string DisplayName { get; set; }
public virtual string EmailAddress { get; set; }
public virtual string Password { get; set; }
public virtual string ProfilePicUrl { get; set; }
public virtual int Money { get; set; }
public virtual DateTime RegistrationDate { get; set; }
}
The table SnappedUsers should contain two foreign keys from the User table.
(it's not necessary that i put an Shooter ISet and an Target ISet to my User class.)
How do i actually have to map these things with XML-mapping? I don't see a solution myself for now.
Thx in advance

<composite-id>
<key-many-to-one name="Shooter" column="shooter_Id" >
<key-many-to-one name="Target" column="target_Id" />
</composite-id>

Related

'FK_Ratings_Users_UserId' on table 'Ratings' may cause cycles or multiple cascade paths

I am trying in .NET EFCore the following Code-First migrations through the entities below
User
[Table("Users")]
public class User
{
[Key]
public int Id { get; set; }
[Required]
[MaxLength(100)]
public string FirstName { get; set; }
[Required]
[MaxLength(100)]
public string LastName { get; set; }
[Required]
[MaxLength(250)]
public string Email { get; set; }
[Required]
[MinLength(8), MaxLength(16)]
public string Password { get; set; }
[Required]
[MinLength(6), MaxLength(15)]
public string Phone { get; set; }
public ICollection<Apartment> Apartments { get; set; }
public ICollection<Rating> Ratings { get; set; }
}
Apartment
[Table("Apartments")]
public class Apartment
{
[Key]
public int Id { get; set; }
[Required]
[MinLength(24), MaxLength(100)]
public string Title { get; set; }
[Required]
[MinLength(24), MaxLength(250)]
public string Address { get; set; }
[Required]
public int Price { get; set; }
[ForeignKey("User")]
public int UserId { get; set; }
public User User {get; set;}
public ICollection<Rating> Ratings { get; set; }
public ICollection<AptCateg> AptsCategs { get; set; }
}
Ratings
[Table("Ratings")]
public class Rating
{
[Key]
public int Id { get; set; }
public int Value { get; set; }
[ForeignKey("Apartment")]
public int ApartmentId { get; set; }
public Apartment Apartment { get; set; }
[ForeignKey("User")]
public int UserId { get; set; }
public User User { get; set; }
}
I use the commands dotnet ef migrations add InitialDatabase but when I try to use dotnet ef database update it throws the following error in cmd, as in the title
'FK_Ratings_Users_UserId' on table 'Ratings' may cause cycles or
multiple cascade paths
I tried adding as in the EFCore tutorial from here the modelBuilder's Cascade behavior but it doesn't work because I am getting the same error. I have also tried doing the answer from here but the implementation for HasRequired isn't working even if try to install EntityFrameworkCore.Tools.
I understand that there is an issue with a circular thingy going on. From my intuition the program doesn't know what to do in the case of deleting a user, if to drop or not its ratings and apartments or some of that sort, and this is why its acting this way but I can't fix the problem.
My question is, how can I solve this issue as I cannot create my database, and thus I cannot continue working on the project.
Thanks!
You'll have to make the user relationship optional on one of the tables like:
public int? UserId { get; set; }
Making the property type nullable tells EF that a cascade delete is not required here.
You are causing a cyclic reference by adding the User and Apartment to the Ratings entity. User and Apartment entities already have a one-to-many relationship to the Ratings collection.
'FK_Ratings_Users_UserId' on table 'Ratings' may cause cycles or
multiple cascade paths
This is how the Ratings entity should look like:
[Table("Ratings")]
public class Rating
{
[Key]
public int Id { get; set; }
public int Value { get; set; }
}

Cached Fetch for User Roles from NHibernate in an MVC App

Using classes like this...
public class Login
{
public virtual Guid LoginId { get; set; }
public virtual string Name { get; set; }
public virtual string Email { get; set; }
public virtual IList<Group> Groups { get; set; }
}
public class Group
{
public virtual Guid GroupId { get; set; }
public virtual string Name { get; set; }
public virtual string Description { get; set; }
public virtual IList<Role> Roles { get; set; }
public virtual IList<Login> Logins { get; set; }
}
public class Role : ITerminable
{
public virtual Guid RoleId { get; set; }
public virtual string DisplayName { get; set; }
public virtual string RoleName { get; set; }
public virtual string Description { get; set; }
}
And an ERD that looks like this...
This is my current query.
var login = loginRepository.Query().Where(x => x.Name == username).FetchMany(x=>x.Groups).ThenFetchMany(x=>x.Roles).SingleOrDefault();
return login.Groups.SelectMany(x => x.Roles).Distinct().ToList();
The problem is that while the first request to my site is always fine and goes through as a single query for the current user's Roles, subsequent ones result in NHibernate Profiler showing lots of cached queries (one for every role). I'm not entirely sure if this is a red flag or not (I'm using SysCache2, but it's not using Database Dependencies at the moment). But I would like to try and find a way to clear itup.
Is there a way to fix this so that I don't get a cache hit for every single role on every request when the first request was just one database hit? Or as an analogy, am I misinterpreting condensation on a pipe as a leak?
Entity cache is separate from the query cache.
The query cache only stores the ids resulting from the query execution, so retrieving the entities back involves getting that list, and then getting all the values from the entity cache.

How to create mapping relationship using Fluent NHibernate

How can I map one-to-many relationship with
User to Address,
Customer to Address,
Agency to Address and
store in a single Address Table using Fluent NHibernate
public class User
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual IList<Address> Address { get; set; }
}
public class Customer
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual IList<Address> Address { get; set; }
}
public class Agency
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual IList<Address> Address { get; set; }
}
public class Address
{
public virtual int Id { get; set; }
public virtual string Address1 { get; set; }
public virtual string Address2 { get; set; }
public virtual string City { get; set; }
public virtual string State { get; set; }
}
I think you'll need to store your relations independently to connect addresses and users/customers/agencies if you want to be able to use the same address for all types. This involves introducing a new table that only stores ID pairs, and making that the storage location for your relationship.
You can map collections as many-to-many and use the table method to name your link table. Your mapping would look something like:
public UserMap : ClassMap<User> {
Id (u => u.Id);
Map (u => u.Name);
HasManyToMany (u => u.Addresses).Table ("UsersXAddresses");
}
You'll need a similar link table for customers and agencies.
In the constructor for your mapping class, map the link using the HasMany method. HasMany will create a one-to-many relationship. HasManyToMany will create a many-to-many relationship.
For example: HasMany(x => x.Address).LazyLoad();
This will create a one-to-many relationship between the User class and the Address class.
For the many-to-many, you will also need to specify the table name and if you so desire, the left and right side table mappings.
For example: HasManyToMany(x => x.Address).Table("AddressToUser").ParentKeyColumn("AddressId").ChildKeyColumn("UserId").LazyLoad();
If you decide that you want to set up a distinction between a UserAddress and an AgencyAddress (where these are sub-classes of Address) - you can use the DiscriminateSubClassesOnColumn method in the AddressMap class so the FNH knows to create an extra column in order to determine which type of object to create.
For example: DiscriminateSubClassesOnColumn("Type").AlwaysSelectWithValue();
You should be able to use FNH Automapping to map these classes "as is".
It will handle all the relationships in your object model.
I believe it will put all the addresses in a single Address table as you desire, but can't say for sure.

NHibernate - QBE

I have a problem using QBE with NHibernate. I have a one-to-one relationship between a Person class and an Employee.
public class Person
{
public virtual Employee Employee { get; set; }
public virtual int Age { get; set; }
public virtual string Forename { get; set; }
public virtual string Surname { get; set; }
public virtual int PersonID { get; set; }
}
public class Employee
{
public virtual int PersonID { get; set; }
public virtual string PayRollNo { get; set; }
public virtual int Holidays { get; set; }
public virtual Person Person { get; set; }
}
As an example, I want to get all Employees where Employee.Forename="John" and Employee.Person.PayRollNo = "231A". I was wondering if I could use Query By Example to do this?
I have not been able to find a definitive "no" but I haven't been able to get this work. I've found that QBE is promising but unfortunately not very useful due to the following limitations:
Cannot query related objects.
Requires public parameterless constructor.
Initialized properties are included in query unless specifically excluded using ExcludeProeprty. For example, bool properties are restricted to false in the where clause, DateTime as DateTime.MinValue. This makes the query very brittle because class modifications may have bad side effects.

Fluent NHibernate Automap Joined Sub-Class Setting the Key

When automapping a joined subclass in fluent nhibernate, I can't figure out how to give the joined subclass a primary key.
public class Address:Entity {
public virtual string Address1 { get; set; }
public virtual string Address2 { get; set; }
public virtual string City { get; set; }
public virtual string State { get; set; }
public virtual string Zip { get; set; }
public virtual string Phone { get; set; }
public virtual string Fax { get; set; }
public virtual IList<Location> Locations { get; set; }
}
public class Location:Address {
public virtual Address BillingAddress { get; set; }
public virtual string OfficeHours { get; set; }
public virtual string PatientAgeRestrictions { get; set; }
public virtual bool WheelchairAccess { get; set; }
public virtual string ContactPerson { get; set; }
public virtual string ContactEmail { get; set; }
public virtual string ContactPhone { get; set; }
public virtual string ContactFax { get; set; }
public virtual string TaxId { get; set; }
}
I want Location to have it's own id "location_ id" with it's own sequence. Then I want that mapped to address through an address_id column.
Right now it's generating the location with "addressid" as the primary key, which isn't what I want. How do I change this with the automapping?
I'm not sure you have a joined-subclass relationship. That is, by definition a joined subclass has the same ID as its parent class. For example, you might have a Person entity stored in your database for generic "people" information like name/age/etc and then an Employee subclass entity which is stored in a different table and holds data like position, salary, and dates of employment. So an Employee is a subtype of Person and to get the full "Employee-Person" object, you must join the two tables on their primary keys (e.g. SELECT * FROM Employee INNER JOIN Person ON Employee.Employee_id = Person.Person_id).
Are you sure about your relational model here? Is Location truly a subtype of Address? Inferring a bit from your property names, it seems to me that this is not what you intend. It seems like you probably have a many-to-many between an Address and an Organization (that is, there may be many "organizations" at the same address and an "organization" may have many addresses), with a "contact person" for the organization at a specific address. In which case you should map "organization", "contact", and another entity that defines the relationship between Address and "organization".