Nested SubClasses with Fluent Nhibernate - fluent-nhibernate

I've seen examples of how to do this with the old subclass syntax, but none with the newer : SubclassMap syntax.
Basically, I have multiple discriminators in a table and need to figure out how to do this with FNH.
Thanks,
Sam

We have a base class User and many derived classes from that as Learners, Assessors, Managers, Admins etc.
here is the UserMap
public class UserMap : ClassMap<User>
{
public UserMap()
{
this.Id(x => x.Id);
this.Map(x => x.Active);
this.Component(
x => x.Address,
m =>
{
m.Map(x => x.Address1).Length(512);
m.Map(x => x.Address2);
m.Map(x => x.Address3);
m.Map(x => x.Address4);
m.Map(x => x.City);
m.Map(x => x.County);
m.Map(x => x.PostCode);
m.References(x => x.Country);
});
this.References(x => x.CreatedBy);
this.Map(x => x.CreatedDate).Not.Nullable();
this.Map(x => x.DeletedDate);
this.References(x => x.DeletedBy);
this.Map(x => x.Email);
this.Map(x => x.Fax);
this.Map(x => x.FirstName);
this.References(x => x.Gender);
this.Map(x => x.LastName);
this.Map(x => x.LoginName).UniqueKey("ui_loginName").Not.Nullable();
this.Map(x => x.MiddleName);
this.Map(x => x.Password);
this.DiscriminateSubClassesOnColumn("className").Length(64);
}
}
and an example of Manager
public class ManagerMap : SubclassMap<Manager>
{
#region Constructors and Destructors
/// <summary>
/// Initializes a new instance of the <see cref="ManagerMap"/> class.
/// </summary>
public ManagerMap()
{
this.HasManyToMany(x => x.Organisation)
.ParentKeyColumn("userId")
.ChildKeyColumn("organisationId")
.Table("UserOrganisations");
this.HasMany(x => x.Learners)
.KeyColumn("managerId")
.AsBag();
}
#endregion
}
Hope that will help you.

Related

Fluent nHibernate mapping with multiple columns

I have following database and I want to create mapping in Fluent nhibernate so that I can traverse object collection like
survey.question.feedback to get all responses to questions .. how can I do that?
I have following mapping so far
public class SurveyMapping : ClassMap<Survey>
{
public SurveyMapping()
{
Id(x => x.Id, "SurveyId");
Map(x => x.Name);
Map(x => x.Type);
Map(x => x.CreationDate);
Map(x => x.ModificationDate);
HasManyToMany<SurveyQuestions>(x => x.Questions).Table("Survey-Questions")
.ParentKeyColumn("SurveyId").ChildKeyColumn("QuestionId").Cascade.All();
HasManyToMany<User>(x => x.Users).Table("User-Surveys").ParentKeyColumn("SurveyId").ChildKeyColumn("UserId").Cascade.None();
}
}
public class SurveyQuestionsMapping : ClassMap<SurveyQuestions>
{
public SurveyQuestionsMapping()
{
Table("Questions");
Id(x => x.Id, "QuestionId");
Map(x => x.QuestionText);
Map(x => x.CommentText);
Map(x => x.Type);
Map(x => x.Scale);
Map(x => x.Rating);
Map(x => x.Threshold);
Map(x => x.CreationDate);
Map(x => x.ModificationDate);
HasMany<UserSurveyFeedback>(x => x.Feedback)
.KeyColumn("QuestionId");
**// This is the confusing part How I can load feedback associated with specific user here**
}
}
You should have many-to-many relations from User to Survey, from User to Feedback, from Question to Survey and from Question to Feedback.
As for querying all feedback from a user, it is simple:
var feedbackFromUser = session.Query<Feedback>().Where(f => f.User.UserID == userID).ToList();

C# NHibernate join problems

I may have possible mapped wrong, or something, NHibernate seems to be confusing to me, but when it works it is smooth. I have Google'd everything to this point and I am still learning NHibernate. I am trying to query an Address that has a accountId, which would link to my AccountUser map, which has a userId that would link to my Usermap. I want to look up all the addresses with the user name of "joe". Anyone know how I would do this with my query? below is my maps, and query:
public AddressMap()
{
Table("Address");
Id(x => x.Id).GeneratedBy.Native();
Map(x => x.FirstName);
Map(x => x.MiddleName);
Map(x => x.LastName);
Map(x => x.CompanyName);
Map(x => x.Street);
Map(x => x.City);
Map(x => x.State);
Map(x => x.AccountID);
Map(x => x.Name);
References(x => x.AccountUser);
}
public class AccountUserMap: ClassMap<AccountUser>
{
public AccountUserMap()
{
Table("AccountUser");
Id(x => x.Id).GeneratedBy.Native();
Map(x => x.UserId);
Map(x => x.AccountID).Not.Nullable();
References(x => x.User);
}
}
public UserMap()
{
Table("User");
Id(x => x.Id).GeneratedBy.Native();
Map(x => x.Name);
}
// non working query:
Address address = null;
User user = null;
AccountUser accountUser = null;
var query = session.QueryOver<Address>(() => address)
.JoinQueryOver(x => x.AccountUser, () => accountUser)
.Where(() => accountUser.AccountID == address.AccountID)
.JoinQueryOver(y => y.User, () => user)
.Where(() => user.Id == accountUser.UserId )
.And(() => user.Name == "joe")
.List()).ToList();
the error message isn't very helpful either...
{"Invalid column name 'AccountUser_id'.\r\nInvalid column name
'User_id'.\r\nInvalid column name 'AccountUser_id'.\r\nInvalid column
name 'User_id'."}
there is nothing named with the underscore, so it must be something with NHibernate
Also, this SQL query below works, and is what I want to do:
SELECT TOP 1000
[AddressID]
,[FirstName]
,[MiddleName]
,[LastName]
FROM Address
inner join AccountUser accountUser
on AccountUser.AccountID = Address.AccountID
inner join User user
on user.UserID = accountUser.UserID
where user.Name= 'joe'
Hopefully thats enough detail
If the property names do not match the database names you have to specify them in the mapping, for example:
Id(x => x.Id, "AddressID").GeneratedBy.Native();
or Fluent NHibernate will use its default naming convention for key columns.

Fluent NHibernate mapping one-to-many

Hello i got problem with my mappings using fluent nhibernate:
public ProductMap()
{
Id(x => x.ProductID);
Map(x => x.ProductName);
Map(x => x.QuantityPerUnit);
Map(x => x.ReorderLevel);
Map(x => x.SupplierID);
Map(x => x.UnitPrice);
Map(x => x.UnitsInStock);
Map(x => x.UnitsOnOrder);
Map(x => x.CategoryID);
Map(x => x.Discontinued);
References(x => x.Category).Column("CategoryID");
References(x => x.Supplier).Column("SupplierID");
Table("dbo.Products");
}
public SupplierMap()
{
Id(x => x.SupplierID);
Map(x => x.Address);
Map(x => x.City);
Map(x => x.CompanyName);
Map(x => x.ContactName);
Map(x => x.ContactTitle);
Map(x => x.Country);
Map(x => x.Fax);
Map(x => x.HomePage);
Map(x => x.Phone);
Map(x => x.PostalCode);
Map(x => x.Region);
HasMany(x => x.Products)
.KeyColumn("SupplierID")
.Inverse()
.Cascade.All();
Table("dbo.Suppliers");
}
public CategoryMap()
{
Id(x => x.CategoryID);
Map(x => x.CategoryName);
Map(x => x.Description);
Map(x => x.Picture);
HasMany(x => x.Products)
.KeyColumn("CategoryID")
.Inverse()
.Cascade.All();
Table("dbo.Categories");
}
when i try to do:
var sessionFactory = SessionFactory.CreateSessionFactory();
using (var session = sessionFactory.OpenSession())
{
Product fresh = new Product()
{
ProductName = "AddFromNhibernate",
SupplierID = 3,
CategoryID = 5,
QuantityPerUnit = "1kg pcg",
UnitPrice = (decimal) 35,
UnitsInStock = (short?) 15,
UnitsOnOrder = 0,
ReorderLevel = null,
Discontinued = true
};
using (session.BeginTransaction())
{
session.Save(fresh);
session.Transaction.Commit();
}
}
I got System.IndexOutOfRangeException.
Whats wrong with my mappings?The work ok when i try to get some data, but adding fails. I trierd to specyfie Propertyreference for Reference in ProductMap but it didn't help.
I noticed you mapped some columns twice.
Take ProductMap as an example:
public ProductMap()
{
(...)
Map(x => x.SupplierID);
(...)
Map(x => x.CategoryID);
References(x => x.Category).Column("CategoryID");
References(x => x.Supplier).Column("SupplierID");
(...)
}
In this case, if you want to preserve the original ID and the reference (since they map to the same column in the database table), you should bypass the Insert/Update in one of them.
What I mean is:
public ProductMap()
{
(...)
Map(x => x.SupplierID).Not.Insert().Not.Update();
(...)
Map(x => x.CategoryID).Not.Insert().Not.Update();
References(x => x.Category).Column("CategoryID");
References(x => x.Supplier).Column("SupplierID");
(...)
}
If you dot not do so, you might get the Exception you described when NHibernate starts to set the insert/update parameters.

Mapping nested components in Fluent NHibernate

I have a 'User' Entity that contains an 'Address' Value Object. I have this mapping ok using FNH's Component concept. However, the Address VO also contains a Country which is another value object. I had assumed that this should be just nested as another component, but this doesn't seem to work. Can anyone tell me how I should solve this?
Code for mapping is below...
Thanks!
public UserMapping()
{
Table("Users");
Id(c => c.Id).GeneratedBy.HiLo("100");
Map(c => c.UserName).Not.Nullable().Length(64);
Map(c => c.Email).Not.Nullable().Length(128);
Map(c => c.Password).Not.Nullable().Length(256);
Map(c => c.Roles).Length(64);
Map(c => c.FirstName).Not.Nullable().Length(64);
Map(c => c.LastName).Not.Nullable().Length(64);
Map(c => c.BirthDate).Not.Nullable();
//Address
Component(x => x.Address, m =>
{
m.Map(x => x.AddressLine1).Not.Nullable();
m.Map(x => x.AddressLine2);
m.Map(x => x.City).Not.Nullable();
m.Map(x => x.Region);
m.Map(x => x.PostalCode).Not.Nullable();
//*****Country Here********
// country has Name and Code
});
}
Ah, Jimmy Bogard from the FNH mailing list showed me - it's quite straightforward. I don't know what I was doing before! Anyway, for anyone else who's interested:
Component(c => c.Address, m =>
{
m.Component(cp => cp.Country, m2 =>
{
m2.Map(x => x.Name); //etc
}
I would create a map for Country and use m.References(x => x.Country).

Fluent Nhibernate Component Prefix

Is there a way to set the column prefix for a component in fluent. For example:
public class SomeClassMap : ClassMap < SomeClass >
{
public SomeClassMap()
{
CreateMap();
}
private void CreateMap()
{
WithTable("Class");
Id(x => x.Id).GeneratedBy.Guid();
Map(x => x.Name).WithLengthOf(100);
Component<SomeComponent>(x => x.somecomponent, m =>
{
m.Map(x => x.Name).SetAttribute("column", "SomeComponentName");
m.Map(x => x.Summary).SetAttribute("column", "SomeComponentSummary");
.... etc ...
}
);
Is there a way to set "SomeComponent" prefixes instead of having to define them in a SetAttribute?
There's nothing implicit. AutoMapping does it, but not regular mapping. I've created an issue so you can track the status of this.
There is some good information here: http://nhforge.org/blogs/nhibernate/archive/2008/09/06/a-fluent-interface-to-nhibernate-part-2-value-objects.aspx that seems to be what you are wanting to do.
In particular the Action method demonstrated in this sample:
public class EmployeeMap : ClassMap<Employee>
{
private Action<ComponentPart<Address>> MapAddress(string columnPrefix)
{
return a =>
{
a.Map(x => x.AddressLine1, columnPrefix + "AddressLine1");
a.Map(x => x.AddressLine2, columnPrefix + "AddressLine2");
a.Map(x => x.PostalCode, columnPrefix + "PostalCode");
a.Map(x => x.City, columnPrefix + "City");
a.Map(x => x.Country, columnPrefix + "Country");
};
}
public EmployeeMap()
{
Id(x => x.Id);
Map(x => x.FirstName).CanNotBeNull().WithLengthOf(20);
Map(x => x.LastName).CanNotBeNull().WithLengthOf(20);
Component<Address>(x => x.HomeAddress, MapAddress("Home_"));
Component<Address>(x => x.WorkAddress, MapAddress("Work_"));
}
}