Problem Understanding Fluent nHibernate Automapping and Relationship - nhibernate

I am a bit new to Fluent nHibernate and ran into a scenario with my schema I'm not sure how to address.
Say I have two tables:
Track
TrackId
UserId
Name
Users
UserId
Name
Now, what I want to do is have the ability to access the related User object by track. For example:
var track = repo.GetById(1);
var userName = track.User.Name;
How can I get nHibernate to automap this new custom User property?

Here you go:
public class Track
{
public virtual int Id {get;set;}
public virtual string Name {get;set;}
public virtual User User {get;set;}
}
public class User
{
public virtual int Id {get;set;}
public virtual string Name {get;set;}
}
// Usage
var track = repo.GetById(1);
var username = track.User.Name;
More information can be found here.

Related

cant create a relationship between application user table and my tables

I'm using entity framework code first. The below keeps kicking out the unable to determine the principal end of an association. Basically I can't figure out how to get one to many relationships between the auto generated identity table and my own tables with code first.
public class applicationUser : Identity
{
public User user {get;set;}
}
//and then a dependant class called User
public class User
{
public in Id {get;set;}
public string Name {get;set;}
[ForeignKey("Identity")]
public string IdentityId {get;set;}
public ApplicationUser Identity {get;set;}
public string UserPicLocation {get;set;}
}
You're using [ForeignKey()] wrong. The value of [ForeignKey()] should be the name of the property that contains the key of the referenced object.
You should also mark the property that contains the key in the referenced object as the private key with [Key]
Try this:
public class applicationUser : Identity
{
public int UserId {get; set;}
[ForeignKey("UserId")]
public User user {get;set;}
}
and then another class called User
public class User
{
[Key]
public int Id {get;set;}
public string Name {get;set;}
public string IdentityId {get;set;}
public ApplicationUser Identity {get;set;}
public string UserPicLocation {get;set;}
}
I fixed it by setting the primary key as both the primary and foreign key in the dependant table

Fluent Nhibernate Cascade.None() results in HasOne foreign key relationship not being persisted

I'm having issues with Nhibernate persisting a HasOne Relationship for one of my entities with Cascade.None() in effect. My domain model involves 4 classes listed below.
public class Project
{
public virtual int Id {get;set;}
public virtual IList<ProjectRole> Team { get; protected set; }
}
public class ProjectRole
{
public virtual int Id { get; set; }
public virtual User User { get; set; }
public virtual Role Role { get; set; }
}
public class Role
{
public virtual int Id { get; set; }
public virtual string Value { get; set; }
}
public class User
{
public virtual int Id { get; protected set; }
public virtual string LoginName { get; set; }
}
So basically we have projects, which have a list of ProjectRoles available from the Team property. Each ProjectRole links a User to the specific Role they play on that project.
I'm trying to setup the following cascade relationships for these entities.
project.HasMany<ProjectRoles>(p=> p.Team).Cascade.All()
projectRole.HasOne<Role>(r => r.Role).Cascade.None()
projectRole.HasOne<User>(r => r.User).Cascade.SaveUpdate()
I've used fluent nhibernate overrides to setup the cascades as above, but I'm finding that the line
projectRole.HasOne<Role>(r => r.Role).Cascade.None()
is resulting in the ProjectRole.Role property not being saved to the database. I've diagnosed this be looking at the SQL Generated by Nhibernate and I can see that the "Role_id" column in the ProjectRoles table is never set on update or insert.
I've also tried using
projectRole.HasOne<Role>(r => r.Role).Cascade.SaveUpdate()
but that fails as well. Unfortunately leaving it Cascade.All() is not an option as that results in the system deleting the Role objects when I try to delete a project role.
Any idea how to setup Cascade.None() for the ProjectRole-> Role relationship with out breaking persistence.
HasOne is for a one-to-one relationship which are rare. You want to use References to declare the one side of a one-to-many relationship. Making some assumptions about your domain model, the mapping should look like:
project.HasMany<ProjectRoles>(p=> p.Team).Inverse().Cascade.AllDeleteOrphan()
projectRole.References<Role>(r => r.Role);
projectRole.References<User>(r => r.User);
See also this question about the difference between HasOne and References.

dapper populate DropDownlist

I have a simple Poco
public virtual short UserID
{
get;
set;
}
[Required]
public virtual string UserName
{
get;
set;
}
public virtual string Password
{
get;
set;
}
public virtual string Email
{
get;
set;
}
Im currently Using Dapper ORM.
Does anyone have a good example of how I would query using dapper ORM to create a drop-down-list?
The query should return Key=UserID and Value=UserName in a list so that I can retrieve the keys and populate the DropDownList.
you can create a class representing the pair:
class SelectItem
{
public long Key {get;set;}
public string Value {get;set;}
}
var list = connection.Query<SelectItem>(" select id Key UserName Value from yourtable",null).ToList();
you use the aliases to map the table fields to the class properties names. I'm supposing your table field names are id and UserName, change them according to your case.
You should also pay attention to the property types, you can have a bad cast exception if they don't match.
ALternatively, you can use the dynamic version:
var list = connection.Query(" select id Key UserName Value from yourtable",null).ToList();
you obtain a list of dynamics each with property named Key and UserName.

Saving multiple child entities in NHibernate, at once

I'm getting the "Save unsaved transient entities" error in NHibernate. I have an aggregate root, neighborhood that contains addresses and person, here's some quick pseudo code to explain the relationship:
public class Neighborhood {
public virtual int Id { get; set; }
public virtual IList<Address> Addresses { get; set; }
}
public class Address {
public virtual int Id { get; set; }
public virtual string Address { get; set; }
public virtual Person Person { get; set; } //Assume only one person per address
}
public class Person {
public virtual int Id { get; set; }
public virtual string Name { get; set; }
}
In my Neighborhood map I have:
mapping.HasMany(x => x.Addresses)
.Inverse()
.KeyColumn("NeighborhoodFk")
.Cascade.All()
.AsBag();
In my code I will often want to create a and associate an Address and Person at the same time:
var address = new Address();
var person = new Person();
var address.Person = person;
var neighborhood = neighborhoodRepository.Get(id);
neighborhood.Add(address);
neighborhoodRepository.DbContext.BeginTransaction();
neighborhoodRepository.SaveOrUpdate(neighborhood);
neighborhoodRepository.DbContext.CommitTransation();
I will get the "unsaved transient entities" error on the Person entity because it is attached to the transient entity Address.
The only way I can see around this is to save the address first, make another call to the database to update neighborhood after the update, search for the address I just added, attach the person and then save again.
Is there something I'm missing to make this easier? This seems like a common use case and I don't want to be making a bunch of roundtrips to the database.
Make sure you're setting the "Cascade" attribute of your mapping from Address to Person to be "save-update" or "all". You have the cascade from Neighborhood to Address, but you didn't state that this lower cascade was present. If it isn't, you're getting this error not because a Person is attached to a transient Address, but because the Address references a transient Person.
If this cascade cannot be made for whatever reason, save the Person first, then save the Neighborhood, which will cascade to the Address, and the ORM will find the referenced Person in its session and set up the reference. This MAY result in some extra "round trips" depending on if you're letting NH or the DB generate autonumber columns. NHibernate is tricky in that it will make DB calls when it's good and ready, and that may be after the entire object graph is in the NH session, or just the person. Either way, it will make an Insert call into the DB for each object being persisted, so it will make multiple "roundtrips" no matter what the code to add the items to the session looks like.

nHibernate Criteria query with missing mapping

I'm trying to do the following thing:
ICriteria criteriaSelect =
session
.CreateCriteria(typeof(Employees))
.CreateCriteria("Orders")
;
var test = criteriaSelect.List<Orders>();
With:
public class Orders{
public virtual int OrderID { get; private set;}
}
public class Employees{
public virtual int EmployeeID { get; private set;}
public virtual IList<Orders> Orders { get; private set; }
}
And I get the error: "No persister for: Employees".
Please note that for decoupling reason, I don't want Orders to
reference Employees.
Thanks for your help,
Stephane
The Criteria API is for indicating the specification you want during the query. You will need to establish mappings for your entities using either the older hbm.xml files or using Fluent NHibernate. See chapter 5 on Basic O/R Mapping for more details.