Reputation: 425
As the title says, Iam getting an error that says: "An invalid or incomplete configuration was used while creating a SessionFactory. Check PotentialReasons collection, and InnerException for more detail."
I'll start with the code.
Database:
User Table:
CREATE TABLE [dbo].[User] (
[Id] UNIQUEIDENTIFIER NOT NULL,
[Username] NVARCHAR (50) NULL,
[PasswordHash] CHAR (64) NOT NULL,
[Salt] CHAR (64) NOT NULL,
[Role] UNIQUEIDENTIFIER NOT NULL,
[Token] NVARCHAR (50) NOT NULL,
[TokenStamp] DATETIME NULL,
CONSTRAINT [PK_User] PRIMARY KEY CLUSTERED ([Id] ASC),
CONSTRAINT [FK_User_Role] FOREIGN KEY ([Role]) REFERENCES [dbo].[Role] ([Id])
);
Role Table:
CREATE TABLE [dbo].[Role] (
[Id] UNIQUEIDENTIFIER NOT NULL,
[Name] NVARCHAR (50) NULL,
CONSTRAINT [PK_Role] PRIMARY KEY CLUSTERED ([Id] ASC)
);
User Class:
using System;
namespace Models
{
public class User : EntityBase
{
public virtual string Username { get; set; }
public virtual string PasswordHash { get; set; }
public virtual string Salt { get; set; }
public virtual Guid Role { get; set; }
public virtual string Token { get; set; }
public virtual DateTime TokenStamp { get; set; }
}
}
Role Class:
namespace Models
{
public class Role : EntityBase
{
public virtual string Name { get; set; }
}
}
EntityBase:
using System;
namespace Models
{
public class EntityBase
{
public virtual Guid Id { get; set; }
}
}
User Map:
using FluentNHibernate.Mapping;
using Models;
namespace NHibernate.Mapping
{
public class UserMap : ClassMap<User>
{
public UserMap()
{
Table("User");
Id(x => x.Id).GeneratedBy.GuidComb();
LazyLoad();
References(x => x.Role).Column("Role");
Map(x => x.Username).Column("Username");
Map(x => x.PasswordHash).Column("PasswordHash").Not.Nullable();
Map(x => x.Salt).Column("Salt").Not.Nullable();
Map(x => x.Token).Column("Token").Not.Nullable();
Map(x => x.TokenStamp).Column("TokenStamp");
}
}
}
Role Map:
using FluentNHibernate.Mapping;
using Models;
namespace NHibernate.Mapping
{
public class RoleMap : ClassMap<Role>
{
public RoleMap()
{
Table("Role");
Id(x => x.Id).GeneratedBy.GuidComb();
LazyLoad();
Map(x => x.Name).Column("Name");
}
}
}
CustomForeignKeyConvention:
using FluentNHibernate;
using FluentNHibernate.Conventions;
namespace NHibernate.Conventions
{
public class CustomForeignKeyConvention : ForeignKeyConvention
{
protected override string GetKeyName(Member property, System.Type type)
{
if (property == null)
{
return type.Name;
}
return property.Name;
}
}
}
Session Factory:
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using NHibernate.Conventions;
namespace NHibernate
{
public static class SessionFactory
{
private static ISessionFactory _sessionFactory;
public static ISessionFactory Instance
{
get
{
if (_sessionFactory == null)
{
_sessionFactory = CreateSessionFactory();
}
return _sessionFactory;
}
}
private static ISessionFactory CreateSessionFactory()
{
return Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2012
.ConnectionString(c => c.FromConnectionStringWithKey("DatabaseConnectionString")))
.Mappings(m =>
{
m.FluentMappings.Conventions.AddFromAssemblyOf<CustomForeignKeyConvention>();
m.FluentMappings.AddFromAssemblyOf<Models.EntityBase>();
})
.BuildSessionFactory();
}
}
}
WebService.cs
using System.Linq;
using System.Net;
using System.Web.Services;
using NHibernate;
using Models;
[WebService(Namespace = "http://LambdAlarm.com/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class LambdAlarmWebService : WebService
{
[WebMethod]
public HttpStatusCode Login(string username, string password)
{
var factory = SessionFactory.Instance;
var session = factory.OpenSession();
var result = session.QueryOver<User>().List<User>();
var login = result.Where(u => u.Username == username).Where(p => p.PasswordHash == password);
return HttpStatusCode.NotFound;
}
}
So yeah... This is not an easy task. I think there is something with the Foreign Key relationship in the database with the User and Role tables. The Role Column shall be referenced to the Id in the Role Table.
Please help!
Upvotes: 7
Views: 32021
Reputation: 1498
If someone else catches this kind of error, please check virtual keyword exists at your entities. For example:
public class Word : IEntity
{
public virtual int WordID { get; set; }
public virtual string WordText { get; set; }
public virtual string Pronunciation { get; set; }
}
Upvotes: 0
Reputation: 109
Although there is a correct answer I will just let another solution others may find useful. This error is caused when your application is not reachable to your database. So:
services.exe
and see if your SQL Server is running or not Upvotes: 5
Reputation: 1944
The problem is that References()
is meant to reference another entity, not a type. If you want to use a type, you should use Map(x => x.Role)
instead of References(x => x.Role)
Change User
to this:
public class User : EntityBase
{
public virtual string Username { get; set; }
public virtual string PasswordHash { get; set; }
public virtual string Salt { get; set; }
public virtual Role Role { get; set; } //CHANGED HERE
public virtual string Token { get; set; }
public virtual DateTime TokenStamp { get; set; }
}
And your UserMap
to:
public UserMap()
{
Table("User");
Id(x => x.Id).GeneratedBy.GuidComb();
LazyLoad();
References(x => x.Role).Column("Role");
Map(x => x.Username).Column("Username");
Map(x => x.PasswordHash).Column("PasswordHash").Not.Nullable();
Map(x => x.Salt).Column("Salt").Not.Nullable();
Map(x => x.Token).Column("Token").Not.Nullable();
Map(x => x.TokenStamp).Column("TokenStamp");
}
Also, there's no reason to specify your column names when you're mapping with Fluent NHibernate. By default it will just use the name of your property, so something like Map(x => x.Name).Column("Name").Not.Nullable()
is just the same as, Map(x => x.Name).Not.Nullable()
Some other suggestions:
Make a base class for your mapping to make it easier:
public abstract class ClassMapBase<T> : ClassMap<T> where T: EntityBase
{
protected ClassMapBase()
{
Id(x => x.Id).Not.Nullable().GeneratedBy.GuidComb();
LazyLoad();
}
}
Also, I'm surprised that NHibernate isn't complaining about your Id
on EntityBase
having a public setter. It should be set to protected or private. There's also no need to specify your table name, unless you want it to be something different than the name of your entity
Upvotes: 6