Lazy Loading child collection with ToFuture - fluent-nhibernate

I'm currently using c# with Nhibernate 3.2 hitting a SqlServer database, and I am trying to work with multiquery's and Futures to load a child collection.
Anyways I can get it to work using Linq to Nhibernate, but when viewing the sql is sent to the database it looks as if it is loading all of the parent objects in addition to the child objects for the child collection fetch (Like it is eager loading). I was curious if it was possible to change this behavior to only pull the needed child object columns.
Here is an example of code that illustrates this issue.
public class Parent : Entity
{
public virtual string Name { get; set; }
public virtual IList<Child> Children { get; set; }
}
public class Child : Entity
{
public virtual int Age { get; set; }
public virtual string Name { get; set; }
public virtual Parent Parent { get; set; }
}
public class ChildClassMap : ClassMap<Child>
{
public ChildClassMap()
{
Id(x => x.Id,"Id");
Map(x => x.Age);
Map(x => x.Name);
this.References(x => x.Parent).Column("ParentId").ForeignKey("Id");
}
}
public class ParentClassMap : ClassMap<Parent>
{
public ParentClassMap()
{
Id(x => x.Id, "Id");
Map(x => x.Name);
this.HasMany(x => x.Children).KeyColumn("ParentId");
}
}
public class FamilyRepository : NHibernateRepository<Parent>
{
public Parent GetParent(int id)
{
using (var session = this.Session.OpenSession())
{
var parent = session.Query<Parent>()
.Where(p => p.Id == id);
parent.FetchMany(x => x.Children)
.ToFuture();
return parent.ToFuture().SingleOrDefault();
}
}
}
Test Case
[TestClass]
public class FamilyTests
{
[TestMethod]
public void Should_Get_Parent_And_Children()
{
// arrange
var repo = new FamilyRepository();
// act
var parent = repo.GetParent(1);
// assert
Assert.AreNotEqual(null, parent);
Assert.AreEqual("TheOldOne", parent.Name);
Assert.AreEqual(3, parent.Children.Count);
Assert.AreEqual(4, parent.Children[1].Age);
Assert.AreEqual("TheMiddleOne", parent.Children[1].Name);
}
}
Sql:
CREATE TABLE [dbo].[Parent](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](50) NOT NULL,
CONSTRAINT [PK_Parent] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[Child](
[Id] [int] IDENTITY(1,1) NOT NULL,
[ParentId] [int] NOT NULL,
[Age] [int] NOT NULL,
[Name] [varchar](50) NOT NULL,
CONSTRAINT [PK_Child] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
ALTER TABLE [dbo].[Child] WITH CHECK ADD CONSTRAINT [FK_Child_Parent] FOREIGN KEY([ParentId])
REFERENCES [dbo].[Parent] ([Id])
GO
ALTER TABLE [dbo].[Child] CHECK CONSTRAINT [FK_Child_Parent]
GO
Set Identity_Insert [dbo].[Parent] on
insert into [dbo].[Parent]
(Id, Name)
values (1, 'TheOldOne');
insert into [dbo].[Parent]
(Id, Name)
values (2, 'TheOtherOne');
Set Identity_Insert [dbo].[Parent] off
GO
Set Identity_Insert [dbo].[Child] on
insert into [dbo].[Child]
(Id, ParentId, Age, Name)
values(1,1,3,'TheYoungOne')
insert into [dbo].[Child]
(Id, ParentId, Age, Name)
values(2,1,4,'TheMiddleOne')
insert into [dbo].[Child]
(Id, ParentId, Age, Name)
values(3,1,7,'TheFirstOne')
Set Identity_Insert [dbo].[Child] off
The output from the sql profiler is:
exec sp_executesql N'
select parent0_.Id as Id3_0_, children1_.Id as Id2_1_, parent0_.Name as Name3_0_, children1_.Age as Age2_1_, children1_.Name as Name2_1_, children1_.ParentId as ParentId2_1_, children1_.ParentId as ParentId0__, children1_.Id as Id0__
from [Parent] parent0_ left outer join [Child] children1_ on parent0_.Id=children1_.ParentId where parent0_.Id=#p0;
select parent0_.Id as Id3_, parent0_.Name as Name3_ from [Parent] parent0_ where parent0_.Id=#p1;
',N'#p0 bigint,#p1 bigint',#p0=1,#p1=1
Does anyone have any suggestions?
thanks for your time

just shorten the code to
public Parent GetParentWithChildrenInitialised(int id)
{
using (var session = SessionFactory.OpenSession())
{
return session.Query<Parent>()
.Where(p => p.Id == id)
.FetchMany(x => x.Children)
.SingleOrDefault();
}
}
I personaly would get rid of the repository because it adds needless abstractions and makes it harder to tune performance, ISession is already like a respository.
A better alternative is to use session.Get(parentId); because this uses the lvl1/session cache or the query above if the children are needed.
Also use the sessionfactory to create sessions because it is threadsafe, sessions are not.

Related

Cannot insert the value NULL into column 'RoleId' (mvc4 simple membership)

I noticed that someone else has faced the same problem such as Cannot insert the value NULL into column 'UserId' but it should be caused by different reasons.
The problem can be simplified like this:
UsersContext _usersContext = new UsersContext();
...
var usersInRole = new UsersInRole() { RoleId = 3, UserId = 1 };
_usersContext.UsersInRoles.Add(usersInRole);
_usersContext.SaveChanges();
The last line of code threw an exception
"An error occurred while updating the entries. See the inner exception
for details."
, and the InnerException was saying the same thing
"An error occurred while updating the entries. See the inner exception
for details."!
Fortunately, the InnerException of the InnerException says
"Cannot insert the value NULL into column 'RoleId', table
'MFC.dbo.webpages_UsersInRoles'; column does not allow nulls. INSERT
fails.\r\nThe statement has been terminated."
. which means "RoleId = 3" was modified or ignored, how could that happen?
Some other code might help are listed below:
[Table("webpages_UsersInRoles")]
public partial class UsersInRole
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int RoleId { get; set; }
public int UserId { get; set; }
}
public class UsersContext : DbContext
{
public UsersContext()
: base("MFCConnectionString")
{
}
public DbSet<UsersInRole> UsersInRoles { get; set; }
}
and table creation scripts:
CREATE TABLE [dbo].[webpages_UsersInRoles] (
[UserId] INT NOT NULL,
[RoleId] INT NOT NULL,
PRIMARY KEY CLUSTERED ([UserId] ASC, [RoleId] ASC),
CONSTRAINT [fk_UsersInRoels_RoleId] FOREIGN KEY ([RoleId]) REFERENCES [dbo].[webpages_Roles] ([RoleId]),
CONSTRAINT [fk_UsersInRoles_UserId] FOREIGN KEY ([UserId]) REFERENCES [dbo].[UserProfile] ([UserId])
);
Another thing intersting is that I can remove an usersInRole from the context, namely, the following code is ok (if I added the record manually):
UsersContext _usersContext = new UsersContext();
...
var usersInRole = _usersContext.UsersInRoles.SingleOrDefault(i => i.RoleId == 3 && UserId == 1);
_usersContext.UsersInRoles.Remove(usersInRole);
_usersContext.SaveChanges();
Seems few people are using and talking simple membership, thus I havevn't found many helpful resource from Google. So any help will be appreciated. Thanks.
Here is the solution:
As Tommy said, this problem is caused by the [Key] attributes.
Rather than deleting the [Key](which will cause an error like "entity type has no key defined"), I changed the code to offical solution:
foreach (var role in roles)
{
foreach (var user in UserProfile.GetAllUserProfiles(_usersContext))
{
var usersInRole = _usersContext.UsersInRoles.SingleOrDefault(uio => uio.RoleId == role.RoleId && uio.UserId == user.UserId);
var key = user.UserId + "_" + role.RoleId;
if (collection.AllKeys.Any(i => i == key) && collection[key].Contains("true") && usersInRole == null)
{
Roles.AddUserToRole(user.UserName, role.RoleName); //Key codes!
}
if (collection.AllKeys.Any(i => i == key) && !collection[key].Contains("true") && usersInRole != null)
{
Roles.RemoveUserFromRole(user.UserName, role.RoleName); //Key codes!
}
}
}
Seems that Roles.AddUserToRole and Roles.RemoveUserFromRole can do it correctly.
But it's not finished yet..... Strangely, _userContext.UsersInRoles cannot return correct results. For example, if the data in table is:
RoleId UserId
5 1
5 2
5 3
it returns 3 records (5,1)(5,1)(5,1) rather than (5, 1)(5, 2)(5, 3). This is the thing Tommy mentioned in his reply but bypassed by Roles.Add/Remove(). The solution is:
1. Add a [ID] column to the table:
CREATE TABLE [dbo].[webpages_UsersInRoles] (
[ID] INT NOT NULL IDENTITY, --Key codes!
[UserId] INT NOT NULL,
[RoleId] INT NOT NULL,
PRIMARY KEY CLUSTERED ([UserId] ASC, [RoleId] ASC),
CONSTRAINT [fk_UsersInRoels_RoleId] FOREIGN KEY ([RoleId]) REFERENCES [dbo].[webpages_Roles] ([RoleId]),
CONSTRAINT [fk_UsersInRoles_UserId] FOREIGN KEY ([UserId]) REFERENCES [dbo].[UserProfile] ([UserId])
);
2. Add the new column to the entity RIGHT UNDER THE [KEY]:
[Table("webpages_UsersInRoles")]
public partial class UsersInRole
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int ID { get; set; } //Key codes!
public int RoleId { get; set; }
public int UserId { get; set; }
}
Now I get (5, 1)(5, 2)(5, 3)!
I know little about database, but as Tommy mentioned, this should be caused by declaring RoleId under [Key][Database....] with PRIMARY KEY CLUSTERED ([UserId] ASC, [RoleId] ASC) in scripts together.
I think your problem is with the following section
public partial class UsersInRole
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int RoleId { get; set; }
public int UserId { get; set; }
}
Having the Key and DatabaseGeneratedAttribute is telling EF that the database is going to assign the value (IDENTITY column). However, your database is not auto assigning this value. So, when EF is trying to do the insert, it is ignoring your RoleId that you assigned because it thinks the database is going to auto assign it. Remove those two attributes on the RoleId property and see if you continue to have the same issues.
1) Why are you using DbContext to add Roles to user? There are some native Membership methods to do it:
Roles.AddUsersToRole(string[] usernames, string rolename)
Roles.AddUserToRole(string username, string rolename) //**This one fits your purpose
Roles.AddUserToRoles(string username, string[] rolenames)
...
2) Value in key column can't be null
3) Int can't be null in C#. If you want to set null value to int, you should define it as nullable: int?

Unidirectional one-to-many NHibernate mapping failing when using FluentNHibernate PersistenceSpecification

I have a domain model where a Order has many LineItems. When I create a new Order (with new LineItems) and use PersistenceSpecification to test the mapping, NHibernate throws a PropertyValueException:
var order = new Order() { LineItems = new List<LineItem>() };
order.LineItems.Add(new LineItem());
new PersistenceSpecification<Order>(session)
.CheckList(o => o.LineItems, order.LineItems) // PropertyValueException
.VerifyTheMappings();
NHibernate.PropertyValueException: not-null property references a null or transient value LineItem._Order.LineItemsBackref
Domain model
public class Order {
public virtual Guid Id { get; set; }
public virtual ICollection<LineItem> LineItems { get; set; }
[...]
}
public class LineItem {
public virtual Guid Id { get; set; }
[...]
}
A LineItem on its own is not interesting, and they will never appear without a Order, so the relationship is unidirectional.
Fluent Mappings/Schema
// OrderMap.cs
Id(x => x.Id).GeneratedBy.GuidComb();
HasMany(x => x.LineItems)
.Not.Inverse()
.Not.KeyNullable()
.Not.KeyUpdate()
.Cascade.AllDeleteOrphan();
// LineItemMap.cs
Id(x => x.Id).GeneratedBy.GuidComb();
// Schema
CREATE TABLE Orders ( Id uniqueidentifier NOT NULL, /* ... */ )
CREATE TABLE LineItems ( Id uniqueidentifier NOT NULL,
OrderId uniqueidentifier NOT NULL, /* ... */ )
The foreign key column in the LineItems table is not nullable, so based on the information in this question I specified Not.KeyNullable() and Not.Inverse() to prevent NHibernate from attempting to insert a LineItem with a NULL Id.
I'm using NHibernate 3.3.2.400 and FluentNHibernate 1.3.0.733 (the current latest versions from NuGet).
This occurs because the CheckList() method tries to save each item in the list as soon as you call it. At this point, the parent entity hasn't been saved yet -- That doesn't happen until you call VerifyTheMappings().
Since the relationship is unidirectional, a child entity (LineItem) can't be persisted unless it is part of a parent (Order), and the exception is thrown. (GitHub issue)
I don't have a solution for this yet other than "don't bother testing the list mapping".

Fluent NHibernate: Mapping HasManyToMany by convention

I'm using Fluent NHibernate's AutoMap feature to map my entities. Most of my entities inherit from a base class Entity which has a property public IList<Tag> Tags.
The tags are in a separate table in the database, so I use a many-to-many relation. But Fluent NHibernate creates mappings for a one-to-many relation.
I'd like to write a convention to override these mappings to use HasManyToMany(...) if the class inherits from Entity. Is this possible and how?
The convention could either rely on the property's type or its name.
Some code for illustration:
// entities
public class Entity
{
public virtual int Id { get; set; }
// ... some other properties
public virtual IList<Tag> { get; set; }
}
public class Tag
{
public virtual int Id { get; set; }
public virtual string TagName { get; set; }
}
public class Event : Entity
{
// ... some properties
}
// Fluent NHibernate configuration
public static ISessionFactory CreateSessionFactory()
{
var config = new CustomAutomappingConfiguration();
return Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2008.ConnectionString(c => c.FromConnectionStringWithKey("Sql")))
.Mappings(m =>
{
m.AutoMappings.Add(AutoMap.AssemblyOf<Event>(config)
.IgnoreBase<Entity>()
.Conventions.Add<CustomForeignKeyConvention>()
.Conventions.Add<CustomManyToManyTableNameConvention>();
})
.BuildSessionFactory();
}
I don't think you can accomplish the mapping with conventions. However, if you want to keep one linking table between the entities and tags, you can do the following:
m.AutoMappings.Add(AutoMap.AssemblyOf<Event>(config)
.IncludeBase<Entity>()
.Override<Entity>(map =>
map.HasManyToMany(e => e.Tags)
.Inverse()
.Cascade.SaveUpdate()));
Notice that I changed IgnoreBase<Entity>() to IncludeBase<Entity>(). This will add an Entity table, but will keep one linking table. With this mapping, you will get the following table DDL:
create table [Entity] (
Id INT IDENTITY NOT NULL,
primary key (Id)
)
create table TagToEntity (
Entity_id INT not null,
Tag_id INT not null
)
create table Event (
Entity_id INT not null,
primary key (Entity_id)
)
create table [Tag] (
Id INT IDENTITY NOT NULL,
TagName NVARCHAR(255) null,
primary key (Id)
)
alter table TagToEntity
add constraint FKD7554554A8C4CA9
foreign key (Tag_id)
references [Tag]
alter table TagToEntity
add constraint FKD75545564C9EC79
foreign key (Entity_id)
references [Entity]
alter table Event
add constraint FKA2FD7DF664C9EC79
foreign key (Entity_id)
references [Entity]
If you choose to do an Override<> per subclass, you will have a linking table per subclass.
In my case, I wanted to use an attribute to indicate a property that should participate in a many-to-many relationship where only one side of the relationship is declared. You could easily modify this to map by other conventions.
Many-to-many relationships are handled by FluentNHibernate.Automapping.Steps.HasManyToManyStep, an IAutomappingStep returned by the DefaultAutomappingConfiguration. This step will only map a property if it discovers a corresponding property of the related type (so both ends of the many-to-many relationship have to be declared).
The approach I've taken is to:
Create a decorator class for HasManyToManyStep that supports detecting and mapping many-to-many properties based on the presence of an attribute (or some other convention)
Create a class derived from DefaultAutomappingConfiguration to when automapping and override GetMappingSteps, wrapping any instance of HasManyToManyStep with the decorator
Here's the decorator, which tries to use the default HasManyToManyStep functionality first. Otherwise, if HasManyToManyAttribute is defined for the member, it will also create the relationship. The code used to create the relationship is nearly identical to the code used by HasManyToManyStep - just without reference to the other side of the relationship.
class ExplicitHasManyToManyStep : IAutomappingStep
{
readonly IAutomappingConfiguration Configuration;
readonly IAutomappingStep DefaultManyToManyStep;
public ExplicitHasManyToManyStep(IAutomappingConfiguration configuration, IAutomappingStep defaultManyToManyStep)
{
Configuration = configuration;
DefaultManyToManyStep = defaultManyToManyStep;
}
#region Implementation of IAutomappingStep
public bool ShouldMap(Member member)
{
if (DefaultManyToManyStep.ShouldMap(member))
{
return true;
}
//modify this statement to check for other attributes or conventions
return member.MemberInfo.IsDefined(typeof(HasManyToManyAttribute), true);
}
public void Map(ClassMappingBase classMap, Member member)
{
if (DefaultManyToManyStep.ShouldMap(member))
{
DefaultManyToManyStep.Map(classMap, member);
return;
}
var Collection = CreateManyToMany(classMap, member);
classMap.AddCollection(Collection);
}
#endregion
CollectionMapping CreateManyToMany(ClassMappingBase classMap, Member member)
{
var ParentType = classMap.Type;
var ChildType = member.PropertyType.GetGenericArguments()[0];
var Collection = CollectionMapping.For(CollectionTypeResolver.Resolve(member));
Collection.ContainingEntityType = ParentType;
Collection.Set(x => x.Name, Layer.Defaults, member.Name);
Collection.Set(x => x.Relationship, Layer.Defaults, CreateManyToMany(member, ParentType, ChildType));
Collection.Set(x => x.ChildType, Layer.Defaults, ChildType);
Collection.Member = member;
SetDefaultAccess(member, Collection);
SetKey(member, classMap, Collection);
return Collection;
}
void SetDefaultAccess(Member member, CollectionMapping mapping)
{
var ResolvedAccess = MemberAccessResolver.Resolve(member);
if (ResolvedAccess != Access.Property && ResolvedAccess != Access.Unset)
{
mapping.Set(x => x.Access, Layer.Defaults, ResolvedAccess.ToString());
}
if (member.IsProperty && !member.CanWrite)
{
mapping.Set(x => x.Access, Layer.Defaults, Configuration.GetAccessStrategyForReadOnlyProperty(member).ToString());
}
}
static ICollectionRelationshipMapping CreateManyToMany(Member member, Type parentType, Type childType)
{
var ColumnMapping = new ColumnMapping();
ColumnMapping.Set(x => x.Name, Layer.Defaults, childType.Name + "_id");
var Mapping = new ManyToManyMapping {ContainingEntityType = parentType};
Mapping.Set(x => x.Class, Layer.Defaults, new FluentNHibernate.MappingModel.TypeReference(childType));
Mapping.Set(x => x.ParentType, Layer.Defaults, parentType);
Mapping.Set(x => x.ChildType, Layer.Defaults, childType);
Mapping.AddColumn(Layer.Defaults, ColumnMapping);
return Mapping;
}
static void SetKey(Member property, ClassMappingBase classMap, CollectionMapping mapping)
{
var ColumnName = property.DeclaringType.Name + "_id";
var ColumnMapping = new ColumnMapping();
ColumnMapping.Set(x => x.Name, Layer.Defaults, ColumnName);
var Key = new KeyMapping {ContainingEntityType = classMap.Type};
Key.AddColumn(Layer.Defaults, ColumnMapping);
mapping.Set(x => x.Key, Layer.Defaults, Key);
}
}
HasManyToManyAttribute class, because there is no other convention I can easily rely on in my case:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class HasManyToManyAttribute : Attribute
{
}
Configuration class derived from DefaultMappingConfiguration class:
class AutomappingConfiguration : DefaultAutomappingConfiguration
{
public override IEnumerable<IAutomappingStep> GetMappingSteps(AutoMapper mapper, IConventionFinder conventionFinder)
{
return base.GetMappingSteps(mapper, conventionFinder).Select(GetDecoratedStep);
}
IAutomappingStep GetDecoratedStep(IAutomappingStep step)
{
if (step is HasManyToManyStep)
{
return new ExplicitHasManyToManyStep(this, step);
}
return step;
}
}

Fluent NHibernate Order by Property in related Entity using QueryOver

I have items and itemgroup tables in my database:
CREATE TABLE [items](
[item_id] [int] IDENTITY(1,1) NOT NULL,
[item_name] [varchar](50) NOT NULL,
[group_id] [int] NOT NULL
)
CREATE TABLE [itemgroup](
[group_id] [int] IDENTITY(1,1) NOT NULL,
[group_name] [varchar](50) NULL
)
and here are mapping classes for these entities:
public class ItemMap : ClassMap<Item>
{
public ItemMap()
{
Table("items");
Id(x => x.Id).Column("item_id");
Map(x => x.Name).Column("item_name");
References(x => x.ItemGroup).Column("group_id").Fetch.Join();
}
}
public class ItemGroupMap : ClassMap<ItemGroup>
{
public ItemGroupMap()
{
Table("itemgroup");
Id(x => x.Id).Column("group_id");
Map(x => x.Name).Column("group_name");
}
}
How can I get all items from the database ordered by group name using QueryOver?
I know how to accomplish it using Criteria (using alias).
var criteria = Session.CreateCriteria<Item>()
.CreateAlias("ItemGroup", "group")
.AddOrder(Order.Asc("group.Name"));
I tried to create ItemGroup alias and use it with QueryOver, but my result was sorted by item name not by itemgroup name.
It would look something like this:
Item itemAlias = null;
ItemGroup itemGroupAlias = null;
session.QueryOver<Item>(() => itemAlias)
.JoinAlias(() => itemAlias.ItemGroup, () => itemGroupAlias)
.OrderBy(() => itemGroupAlias.Name).Asc;

At a loss, how to map two classes in Nhibernate

Please forgive the clumsy question (if you can figure out a better way to word the question feel free to edit away).
I have two classes SupportTicketCategory and SupportTicket (respectively):
public class SupportTicketCategory
{
public SupportTicketCategory()
{ }
private int _supportTicketCategoryID;
public virtual int SupportTicketCategoryID
{
get { return _supportTicketCategoryID; }
set
{
_supportTicketCategoryID = value;
}
}
private string _supportTicketCategoryName;
public virtual string SupportTicketCategoryName
{
get { return _supportTicketCategoryName; }
set
{
_supportTicketCategoryName = value;
}
}
}
and
public SupportTicket()
{ }
private int _supportTicketID;
public virtual int SupportTicketID
{
get { return _supportTicketID; }
set
{
_supportTicketID = value;
}
}
private SupportTicketCategory _supportTicketCategory;
public virtual SupportTicketCategory SupportTicketCategory { get; set; }
My table structure is as follows:
CREATE TABLE [dbo].[supporttickets](
[supportticketid] [int] IDENTITY(1,1) NOT NULL,
[supportticketcategoryid] [int] NOT NULL,
CONSTRAINT [PK_supporttickets] PRIMARY KEY CLUSTERED
(
[supportticketid] ASC
)
) ON [PRIMARY]
ALTER TABLE [dbo].[supporttickets]
WITH CHECK ADD CONSTRAINT
[FK_supporttickets_supportticketcategories]
FOREIGN KEY([supportticketcategoryid])
REFERENCES [dbo].[supportticketcategories] ([supportticketcategoryid])
ALTER TABLE [dbo].[supporttickets] CHECK CONSTRAINT [FK_supporttickets_supportticketcategories]
CREATE TABLE [dbo].[supportticketcategories](
[supportticketcategoryid] [int] IDENTITY(1,1) NOT NULL,
[supportticketcategoryname] [varchar](50) NOT NULL,
CONSTRAINT [PK_supportticketcategories] PRIMARY KEY CLUSTERED
(
[supportticketcategoryid] ASC
)
) ON [PRIMARY]
So basically, I want to map a SupportTicketCategory onto the SupportTicket like it is in my class, however I cannot figure out what is the proper mapping type and cannot find an example of this on the interwebs.
Update:
I changed the SupportTicketCategory property to old school getters and setters and it worked...syntax sugar for loss.
If you use MyGeneration with the NHibernate template, you can point it at your database and it will make the mappings for you, so you can see how it ought to be done.
I think what you're looking for is the "many-to-one" element. (This goes inside your class element for SupportTicket)
<many-to-one name="SupportTicketCategory" column="SupportTicketCategoryId" update="false" insert="false" />
Many to one mappings can be done like this:
<many-to-one name="SupportTicketCategory" class="SupportTicketCategory" not-null="false" column="SupportTicketCategoryId" />