Fluent NHibernate without Automapping SQL Exception, Incorrect syntax near the keyword 'User' - nhibernate

Just starting in NHibernate and to my eye Everything seems correct but obviously is not. When I ren unit tests shown below I receive back that there is a syntax error near the keyword "User"
here is my user class:
namespace Users
{
public class User
{
public virtual string firstName { get; set; }
public virtual string lastName { get; set; }
public virtual int Id { get; set; }
}
}
and the User mapping(Also ran without square brackets around column names with identical results:
namespace Users
{
class UserMap: ClassMap<User>
{
UserMap()
{
Table("User");
Id(x => x.Id).GeneratedBy.Native().Column("[Id]").Not.Nullable();
Map(x => x.firstName).Not.Nullable().Column("[firstName]");
Map(x => x.lastName).Not.Nullable().Column("[lastName]");
}
}
}
The Config file named Framework.cs
namespace Users
{
public class Framework
{
private const string ConnectionStr = "Data Source=ERALCH-ESTEPHEN;Initial
Catalog=NHDev;Integrated Security=True;Pooling=False";
public static ISessionFactory CreateFactory()
{
return Fluently.Configure()
.Database(FluentNHibernate.Cfg.Db.MsSqlConfiguration
.MsSql2008
.ConnectionString(ConnectionStr))
.Mappings(x=>x.FluentMappings.AddFromAssemblyOf<User>())
.BuildSessionFactory();
}
}
}
The Data Access Layer-- simply retrieves a user by Id
namespace Users
{
public class Accesslayer
{
public static IList<User> GetUserById(int Id)
{
ISessionFactory provider = Framework.CreateFactory();
using (ISession session = provider.OpenSession())
{
return session.CreateSQLQuery(String
.Format("SELECT * FROM User WHERE Id={0}", Id)).List<User>();
}
}
}
}
and finally the unit test layer
namespace Users
{
[TestFixture]
class AccessLayerTest
{
[Test]
public void CanGetUserById()
{
Assert.AreEqual(1, Accesslayer.GetUserById(1).Count());
}
}
}
The Database is MSsql with one table "User" with columns matching the user properties. Any help would be appreciated thanks

You should be able to do this in your configuration:
var factory = Fluently.Configure()
// ...
.ExposeConfiguration(c => SchemaMetadataUpdater.QuoteTableAndColumns(c))
.BuildSessionFactory();
Which should escape your table and column names for you automagically.

Did you try putting backticks around your User table name ?
namespace Users
{
class UserMap: ClassMap<User>
{
UserMap()
{
Table("`User`");
Id(x => x.Id).GeneratedBy.Native().Column("`Id`").Not.Nullable();
Map(x => x.firstName).Not.Nullable().Column("`firstName`");
Map(x => x.lastName).Not.Nullable().Column("`lastName`");
}
}
}
See this answer for more details : NHibernate - Force escaping on Table Names
Also, you should use NHibernate querying facilities instead of SQL :
namespace Users
{
public class Accesslayer
{
public static IList<User> GetUserById(int Id)
{
ISessionFactory provider = Framework.CreateFactory();
using (ISession session = provider.OpenSession())
{
return session.Query<User>().Where(x => x.Id == Id ).List<User>();
}
}
}
}
Have a look at this tutorial : http://www.d80.co.uk/post/2011/02/20/Linq-to-NHibernate-Tutorial.aspx

You should need the [Brackets] while mapping. Heck, if they have the same name, both of these would work the same:
public class UserMap: ClassMap<User>
{
UserMap()
{
Table("User");
Id(x => x.Id).GeneratedBy.Native().Not.Nullable();
Map(x => x.firstName).Not.Nullable();
Map(x => x.lastName).Not.Nullable();
}
}
public class UserMap: ClassMap<User>
{
UserMap()
{
Table("User");
Id(x => x.Id, "Id").GeneratedBy.Native().Not.Nullable();
Map(x => x.firstName, "firstName").Not.Nullable();
Map(x => x.lastName, "lastName").Not.Nullable();
}
}

Avoid naming your tables or columns using Reserved Keywords. Hibernate forms a SQL-Statement which won't be accepted by MS SQL. Had the same problem with NHibernate + Fluent + Automapper and solved it by renaming the "user"-column to "username". Don't know how other DBs handle it.
Further comments about this here.

Related

Table-per-subclass fluent nhibernate not working

I have the following classes defined:
And these tables in my database:
My fluent NHibernate mappings are:
public class BusinessUnitMap : ClassMap<BusinessUnit>
{
public BusinessUnitMap()
{
Table("BusinessUnits");
Id(x => x.Id);
Map(x => x.Code);
Map(x => x.Name);
Map(x => x.ParentId);
Map(x => x.Type).Column("Type").CustomType<BusinessUnitType>();
}
}
public class CompanyMap : SubclassMap<Company>
{
public CompanyMap()
{
Table("CompanyData");
KeyColumn("BusinessUnitID");
Map(x => x.Something);
}
}
public class FranchiseeMap : SubclassMap<Franchisee>
{
public FranchiseeMap()
{
Table("FranchiseeData");
KeyColumn("BusinessUnitID");
Map(x => x.SomethingDifferent);
}
}
public class StoreMap : SubclassMap<Store>
{
public StoreMap()
{
Table("StoreData");
KeyColumn("BusinessUnitID");
Map(x => x.SomethingElse);
}
}
Question #1
As far as I can tell, my code and database are setup the same as every example I've been able to find. According to those articles, NHibernate is supposed to be smart enough to determine what subclass to instantiate when I query for a particular subclass. But, when I execute the following statement:
var result = Session.QueryOver<BusinessUnit>()
.Where(x => x.Code == "Acme")
.SingleOrDefault();
an exception is thrown because it can't create an instance of the abstract BusinessUnit class. The only way I can get this to work is to specify Company as the type argument for QueryOver.
I've confirmed that using a discriminator breaks since NHibernate is looking for all of the columns to exist in a single table. Without it, though, I struggle to see how NHibernate would know what type to instantiate.
What am I doing wrong? Is the problem in my mappings, the way I'm querying, ...?
Question #2
When I change the query to something like this:
public T WithCode<T>(String code)
where T : BusinessUnit
{
var result = Session.QueryOver<T>()
.Where(x => x.Code == code)
.SingleOrDefault();
return result;
}
I get an exception indicating that the UPDATE statement conflicts with a foreign key constraint. Update statement!!!! Clearly something is still not right. How can a QueryOver call result in an UPDATE statement? What am I missing?
it looks like your data is not consistent. It might be better to use discrimnator mapping with optional. If you dont really need a BusinessUnitType property in code then just delete everything around the property Type
public enum BusinessUnitType
{
Company,
Franchisee
}
public abstract class BusinessUnit
{
public virtual int Id { get; set; }
public virtual string Code { get; set; }
public virtual string Name { get; set; }
public virtual BusinessUnit Parent { get; set; }
public abstract BusinessUnitType Type { get; }
}
public class Company : BusinessUnit
{
public virtual string Something { get; set; }
public override BusinessUnitType Type { get { return BusinessUnitType.Company; } }
}
public class Franchisee : BusinessUnit
{
public virtual string SomethingDifferent { get; set; }
public override BusinessUnitType Type { get { return BusinessUnitType.Franchisee; } }
}
public class BusinessUnitMap : ClassMap<BusinessUnit>
{
public BusinessUnitMap()
{
Table("BusinessUnits");
Id(x => x.Id);
Map(x => x.Code);
Map(x => x.Name);
References(x => x.Parent);
DiscriminateSubClassesOnColumn("Type");
Map(x => x.Type, "Type")
.Access.None()
.CustomType<BusinessUnitType>().ReadOnly();
}
}
public class CompanyMap : SubclassMap<StrangeTablePerSubclass.Company>
{
public CompanyMap()
{
DiscriminatorValue((int)new Company().Type);
Join("CompanyData", join =>
{
join.KeyColumn("BusinessUnitID");
join.Optional();
join.Map(x => x.Something);
});
}
}
public class FranchiseeMap : SubclassMap<Franchisee>
{
public FranchiseeMap()
{
DiscriminatorValue((int)new Franchisee().Type);
Join("FranchiseeData", join =>
{
join.KeyColumn("BusinessUnitID");
join.Optional();
join.Map(x => x.SomethingDifferent);
});
}
}

Map One-To-One Relationship Doesn't Allow Inserting

I'm trying to setup a one-to-one mapping from my Users to the UserDetails table. Say I have the following tables in my database:
Users:
- UserID (PK, Identity)
- UserName
- Password
UsersDetails:
- UserID (PK, FK)
- FirstName
- LastName
I have created the following poco classes:
public class User {
public virtual int UserID { get; set; }
public virtual string UserName { get; set; }
public virtual string Password { get; set; }
public virtual UserDetails Details { get; set; }
}
public class UserDetails {
public virtual int UserID { get; set; }
public virtual User User { get; set; }
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
public UserDetails() {
}
public UserDetails(User user) {
User = user;
}
}
Which are fluently mapped (please note the xml mapping is very similar and if all you know is the xml mapping then I would still appreciate you guidance):
public class UserMap : ClassMap<User> {
public UserMap() {
Table("Users");
Id(x => x.UserID);
Map(x => x.UserName);
Map(x => x.Password);
HasOne(x => x.Details)
.Constrained()
.Cascade.All();
}
}
public class UserDetailsMap : ClassMap<UserDetails> {
public UserDetailsMap() {
Table("UsersDetails");
Id(x => x.UserID)
.GeneratedBy.Foreign("User");
HasOne(x => x.User)
.Constrained();
Map(x => x.FirstName);
Map(x => x.LastName);
}
}
Everything displays correctly but if I say:
var user = new User() { UserName = "Test", Password = "Test" };
user.Details = new UserDetails(user) { FirstName = "Test", LastName = "Test" };
session.Save(user);
I get the error:
"NHibernate.Id.IdentifierGenerationException: null id generated for: UserDetails."
I'd really appreciate it if someone could show me what I've done wrong. Thanks
Edit: Courtesy of Jamie Ide's suggestion. I have changed my User mapping to:
public class UserMap : ClassMap<User> {
public UserMap() {
Table("Users");
Id(x => x.UserID);
Map(x => x.UserName);
Map(x => x.Password);
References(x => x.Details, "UserID")
.Class<UserDetails>()
.Unique();
}
}
But now when i insert a user i get the error:
"System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection."
If i add Cascade.All() on to my Reference i receive the original error i was getting about the null id generated.
I think Constrained should only be specified in the UserDetailsMap, not in the UserMap. Try:
public class UserMap : ClassMap<User> {
public UserMap() {
Table("Users");
Id(x => x.UserID);
Map(x => x.UserName);
Map(x => x.Password);
HasOne(x => x.Details)
.Cascade.All();
}
}
EDIT:
See this and this. It appears that you have to map the relationship as many-to-one from the User side and one-to-one constrained from the UserDetails side to get lazy loading working with one-to-one. I don't know if this is different in NH3.
I am not sure the way you are mapping the ID property is correct. shouldnt it just be an autoincremented id and your mapping should be as follows:
Id(x=>x.UserId);
I dont know the idea behind using Foreign and how it fits into things here.. can you please illustrate the logic behind that?
I think you need to have the foreign key identity mapping in your User mapping instead of the UserDetails and the native one in the UserDetails. I have been unable to find a reference for it, though.
http://gorbach.wordpress.com/2010/09/24/fluent-onetoone/
HasOne(x => x.Details).Cascade.All().ForeignKey("UserDetails");
HasOne(x => x.User).Constrained();
var user = new User() { UserName = "Test", Password = "Test" };
user.Details = new UserDetails(user) { FirstName = "Test", LastName = "Test" };
user.Details.User = user;
session.Save(user);
After further research it appears that this won't work in version 2.0. I am now in a position to upgrade to version 3.0 where i believe this is now possible.

FluentNHibernate IDctionary with manytomany

I have a mapping structured in this way:
public class Person
{
public IDictionary<bool, Action> Actions { get; set; }
}
public class Action
{
public string Name { get; set; }
}
// Map for Person
public class PersonMap : ClassMap<Person>
{
public PersonMap()
{
Id(x => x.Id) ...
Map(x => x.Name) ...
Table("Persons")
}
}
// Map for Action
public class ActionMap : ActionMap<Action>
{
public ActionMap()
{
Id(x => x.Id) ...
Map(x => x.Name) ...
Table("Actions")
}
}
What I need to do now is this.
I need a third table that will contains this fields:
PersonId
ActionId
True/false
Because I have the collection of actions inside the class person i was thinking about using a manytomany, but I can't find documentation on how to map an IDictionary.
Any idea? Wrong approach?
Dunno if you've already found the solution but there's been a recent update(only a couple weeks ago) where you could simply map it as HasManyToMany(x => x.NameOfDictionary) so you might want to update your FNH.
I haven't tried it yet though but here's the link: mailing list post

nhibernate mapping: A collection with cascade="all-delete-orphan" was no longer referenced

I am having some probs with my fluent mappings. I have an entity with a child collection of entities i.e Event and EventItems for example.
If I set my cascade mapping of the collection to AllDeleteOrphan I get the following error when saving a new entity to the DB:
NHibernate.HibernateException : A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance: Core.Event.EventItems
If I set the cascade to All it works fine? Below are my classes and mapping files:
public class EventMap : ClassMap<Event>
{
public EventMap()
{
Id(x => x.Id, "Id")
.UnsavedValue("00000000-0000-0000-0000-000000000000")
.GeneratedBy.GuidComb();
Map(x => x.Name);
HasMany(x => x.EventItems)
.Inverse()
.KeyColumn("EventId")
.AsBag()
.Cascade.AllDeleteOrphan();
}
}
public class EventItemMap : SubclassMap<EventItem>
{
public EventItemMap()
{
Id(x => x.Id, "Id")
.UnsavedValue("00000000-0000-0000-0000-000000000000")
.GeneratedBy.GuidComb();
References(x => x.Event, "EventId");
}
}
public class Event : EntityBase
{
private IList<EventItem> _EventItems;
protected Event()
{
InitMembers();
}
public Event(string name)
: this()
{
Name = name;
}
private void InitMembers()
{
_EventItems = new List<EventItem>();
}
public virtual EventItem CreateEventItem(string name)
{
EventItem eventItem = new EventItem(this, name);
_EventItems.Add(eventItem);
return eventItem;
}
public virtual string Name { get; private set; }
public virtual IList<EventItem> EventItems
{
get
{
return _EventItems.ToList<EventItem>().AsReadOnly();
}
protected set
{
_EventItems = value;
}
}
}
public class EventItem : EntityBase
{
protected EventItem()
{
}
public EventItem(Event #event, string name):base(name)
{
Event = #event;
}
public virtual Event Event { get; private set; }
}
Pretty stumped here. Any tips greatly appreciated.
Chev
You need to map _EventItems using an access strategy so that NHibernate access the private member instead of the property. You're getting this error because the collection reference is changed when the list is copied to a new List in _EventItems.ToList<EventItem>(). Try this:
public class EventMap : ClassMap<Event>
{
public EventMap()
{
Id(x => x.Id, "Id")
.UnsavedValue("00000000-0000-0000-0000-000000000000")
.GeneratedBy.GuidComb();
Map(x => x.Name);
HasMany(x => x.EventItems)
.Access.PascalCaseField(Prefix.Underscore)
.Inverse()
.KeyColumn("EventId")
.AsBag()
.Cascade.AllDeleteOrphan();
}
}
}
I don't think the accepted answer is an elegant approach. The possible problem here is that Chev is reading Events from the database and then assigning a new EventItem list to the EventItems property. NHibernate throws this exception when you just ignore the previous children list and assign a new children list.
What you need to do here is,
If you want to discard the old EventItems, do this instead:
events.EventItems.Clear();
events.EventItems.Add(new EventItem { blah blah });
Check this SO post: NHibernate: Delete a child record from the parent collection
The comments to the accepted answer has similar issue.
You may want to try removing AsReadOnly for your EventItems to check if that's the cause.

How to map part of aspnet_Users table using Fluent NHibernate

I'm trying to get Fluent NHibernate 1.0 RTM to map a User entity for me so that I have access to UserId and UserName inside my ASP.NET MVC application via NHibernate.
I have:
public class User
{
public virtual Guid UserId { get; protected set; }
public virtual string UserName { get; protected set; }
}
It represents the aspnet_Users table with only the relevant columns to be mapped. This is the only entity that is not being automapped. Here is my mapping:
public class UserMap : ClassMap<User>
{
public UserMap()
{
Id(x => x.UserId);
Map(x => x.UserName);
WithTable("aspnet_Users");
}
}
Everything else is getting automapped with conventions.
Here are my PrimaryKeyConvention and TableNameConvention:
public class PrimaryKeyConvention : IIdConvention
{
public void Apply(IIdentityInstance instance)
{
instance.Column(instance.Property.ReflectedType.Name + "Id");
instance.UnsavedValue(System.Guid.Empty.ToString());
instance.GeneratedBy.GuidComb();
}
}
public class TableNameConvention : IClassConvention
{
public void Apply(IClassInstance instance)
{
instance.Table(Inflector.Net.Inflector.Pluralize(instance.EntityType.Name));
}
}
The Mapping process fails right after executing the ClassMap code (which comes before all automapping), followed by the TableNameConvention code, followed by the PrimaryKeyConvention code. The failure is in PrimaryKeyConvention because instance.Property is null. I tried to do an if(instance.Property != null) but that
terminates the mapping process early with a "the required attribute 'class' is missing" error. I also had an if (instance.EntityType != typeof(User)) in the TableNameConvention, but took out when it was making no difference.
What is going on here? First of all, why is the AutoMapping processes calling the conventions for the ClassMap? Second, why is the PrimaryKenConvention getting passed an instance.Property == null? How can I get this to work so that the mapping process moves on and maps the rest of my entities using AutoMapping + conventions?
Note, I had this all working for months under an earlier version of FNH prior to the refactor for 1.0 RTM.
I've figured out the answer to this.
public UserMap()
{
Id(x => x.UserId);
Map(x => x.UserName);
Table("aspnet_Users");
}
public class PrimaryKeyConvention : IIdConvention
{
public void Apply(IIdentityInstance instance)
{
instance.Column(instance.EntityType.Name + "Id");
instance.UnsavedValue(System.Guid.Empty.ToString());
instance.GeneratedBy.GuidComb();
}
}
public class TableNameConvention : IClassConvention
{
public void Apply(IClassInstance instance)
{
instance.Table(Inflector.Net.Inflector.Pluralize(instance.EntityType.Name));
}
}
Note that the PrimaryKeyConvention sets the Column name using instance.EntityName rather that instance.Property. The latter was null for the UserMap, so it would crash.
This approach is better than using a conditional statement on (null != instance.Property) and keeping the instance.Property.ReflectedType.Name line, but both work. If you choose to go that route, you have to explicitly set the Column names in the UserMap:
public UserMap()
{
Id(x => x.UserId).Column("UserId")
.GeneratedBy.Assigned();
Map(x => x.UserName).Column("UserName");
Table("aspnet_Users");
}
I don't use the auto-mapping myself, but I think you need to map User by implementing IAutoMappingOverride. Something like:
public class UserMap : IAutoMappingOverride<User>
{
public void Override(AutoMapping<User> mapping)
{
mapping.Id(x => x.UserId);
mapping.Map(x => x.UserName);
mapping.WithTable("aspnet_Users");
}
}