Issues with Fluent Nhibernate Automapping in version 1.0RC - sql-server

I am new to NHibernate and am running into some issues getting the Automap functionality to work properly. Here are a couple of issues I am having.
The getting started wiki for Fluent NHibernate (http://wiki.fluentnhibernate.org/Getting_started) defines a sample with store, product, and employee classes--as well as the mapping for those classes. I replaced the manual mapping with AutoMapping and used Fluent NHibernate to generate the schema. Every thing generated properly. However, when the application attempted to save sample store, product, and employee objects, I received an error "TransientObjectException was Unhandled: object references an unsaved transient instance - save the transient instance before flushing. Type: FluentExample.Entities.Employee, Entity: FluentExample.Entities.Employee".
The automap looks like:
.Mappings(m=>
m.AutoMappings.Add(
AutoMap.AssemblyOf<FluentExample.Entities.Employee>(type => type.Namespace == "FluentExample.Entities")))
The object creation code (straight from the wiki) looks like the following. I should mention that the object creation works fine when using the manual fluent mapping.
// create a couple of Stores each with some Products and Employees
var barginBasin = new Store { Name = "Bargin Basin" };
var superMart = new Store { Name = "SuperMart" };
var potatoes = new Product { Name = "Potatoes", Price = 3.60 };
var fish = new Product { Name = "Fish", Price = 4.49 };
var milk = new Product { Name = "Milk", Price = 0.79 };
var bread = new Product { Name = "Bread", Price = 1.29 };
var cheese = new Product { Name = "Cheese", Price = 2.10 };
var waffles = new Product { Name = "Waffles", Price = 2.41 };
var daisy = new Employee { FirstName = "Daisy", LastName = "Harrison" };
var jack = new Employee { FirstName = "Jack", LastName = "Torrance" };
var sue = new Employee { FirstName = "Sue", LastName = "Walkters" };
var bill = new Employee { FirstName = "Bill", LastName = "Taft" };
var joan = new Employee { FirstName = "Joan", LastName = "Pope" };
// add products to the stores, there's some crossover in the products in each
// store, because the store-product relationship is many-to-many
AddProductsToStore(barginBasin, potatoes, fish, milk, bread, cheese);
AddProductsToStore(superMart, bread, cheese, waffles);
// add employees to the stores, this relationship is a one-to-many, so one
// employee can only work at one store at a time
AddEmployeesToStore(barginBasin, daisy, jack, sue);
AddEmployeesToStore(superMart, bill, joan);
// save both stores, this saves everything else via cascading
session.SaveOrUpdate(barginBasin);
session.SaveOrUpdate(superMart);
transaction.Commit();
When attempting to use the AutoMap functionality on one of my own classes, a class is
created, but for some reason I get errors when I attempt to actually
insert a record. The main error message says "AssertionFailure was
unhandled: null value". Here is a sample of my class, the config/
mapping, the error, and the create table script. (Note: The attributes
in the class are for use with ASP.NET MVC and have nothing to do with
NH.)
namespace Credit.Data.Entities
{
[Serializable]
public class EthnicityType
{
public EthnicityType()
{
}
[DisplayName("Id")]
[Required(ErrorMessage = "Id is required.")]
public virtual Guid Id { get; private set; }
[DisplayName("Title")]
[Required(ErrorMessage = "Title is required.")]
[StringLength(80, ErrorMessage = "Title must be less than 80 characters.")]
public virtual string Title { get; set; }
[DisplayName("Description")]
[StringLength(255, ErrorMessage = "Description must be less than 255 characters.")]
public virtual string Description { get; set; }
[DisplayName("Is Active")]
[Required(ErrorMessage = "Is Active is required.")]
public virtual bool IsActive { get; set; }
}
}
Here is the Fluent NHibernate configuration.
private static ISessionFactory CreateSessionFactory()
{
return Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2008
.ConnectionString(c => c.FromConnectionStringWithKey ("CreditConnectionString"))
.UseReflectionOptimizer()
.AdoNetBatchSize(25)
.DefaultSchema("dbo")
.Cache(c => c
.UseQueryCache()
.ProviderClass<HashtableCacheProvider>())
.ShowSql())
.Mappings(m =>
m.AutoMappings.Add(AutoMap.AssemblyOf<Credit.Data.Entities.EthnicityType>(type => type.Namespace == "Credit.Data.Entities")))
.ExposeConfiguration(BuildSchema)
.BuildSessionFactory();
}
And the error. Yuk!
NHibernate.AssertionFailure was unhandled
Message="null identifier"
Source="NHibernate"
StackTrace:
at NHibernate.Engine.EntityKey..ctor(Object identifier, String
rootEntityName, String entityName, IType identifierType, Boolean
batchLoadable, ISessionFactoryImplementor factory, EntityMode
entityMode)
at NHibernate.Engine.EntityKey..ctor(Object id,
IEntityPersister persister, EntityMode entityMode)
at
NHibernate.Event.Default.AbstractSaveEventListener.PerformSaveOrReplicate
(Object entity, EntityKey key, IEntityPersister persister, Boolean
useIdentityColumn, Object anything, IEventSource source, Boolean
requiresImmediateIdAccess)
at
NHibernate.Event.Default.AbstractSaveEventListener.PerformSave(Object
entity, Object id, IEntityPersister persister, Boolean
useIdentityColumn, Object anything, IEventSource source, Boolean
requiresImmediateIdAccess)
at
NHibernate.Event.Default.AbstractSaveEventListener.SaveWithGeneratedId
(Object entity, String entityName, Object anything, IEventSource
source, Boolean requiresImmediateIdAccess)
at
NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.SaveWithGeneratedOrRequestedId
(SaveOrUpdateEvent event)
at
NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.EntityIsTransient
(SaveOrUpdateEvent event)
at
NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.PerformSaveOrUpdate
(SaveOrUpdateEvent event)
at
NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.OnSaveOrUpdate
(SaveOrUpdateEvent event)
at NHibernate.Impl.SessionImpl.FireSaveOrUpdate
(SaveOrUpdateEvent event)
at NHibernate.Impl.SessionImpl.SaveOrUpdate(Object obj)
at FluentExample.Program.PopulateRecordTest(ISessionFactory
sessionFactory) in C:\Code\FluentExample\FluentExample\Program.cs:line
52
at FluentExample.Program.BootstrapNH() in C:\Code\FluentExample
\FluentExample\Program.cs:line 32
at FluentExample.Program.Main() in C:\Code\FluentExample
\FluentExample\Program.cs:line 24
at System.AppDomain._nExecuteAssembly(Assembly assembly, String
[] args)
at
Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ExecutionContext.Run(ExecutionContext
executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
InnerException:
And the table schema--just for kicks.
USE [Credit]
GO
/****** Object: Table [dbo].[EthnicityType] Script Date:
08/30/2009 04:59:31 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[EthnicityType](
[ID] [uniqueidentifier] NOT NULL,
[Title] [nvarchar](80) NOT NULL,
[Description] [nvarchar](255) NULL,
[IsActive] [bit] NOT NULL
CONSTRAINT [PK_EthnicityType_Title] PRIMARY KEY NONCLUSTERED
(
[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
ALTER TABLE [dbo].[EthnicityType] ADD CONSTRAINT
[DF_EthnicityType_ID] DEFAULT (newid()) FOR [ID]
GO
ALTER TABLE [dbo].[EthnicityType] ADD CONSTRAINT
[DF_EthnicityType_IsActive] DEFAULT ((1)) FOR [IsActive]
GO
I've tried a number of things to get automapping working in my environment but just have not yet been fully successful. Some variations I have tried include
Using a static map and allowing Fluent Nhibernate to recreate my table.
Changing the private set on Id to public
Creating a primarykeyconvention to try and set the Guid in case that was the issue and adding this to my mapping.
Primary Key Convention:
public class PrimaryKeyConvention : IIdConvention
{
public void Apply(IIdentityInstance instance)
{
instance.GeneratedBy.GuidComb();
//instance.GeneratedBy.Native();
}
}
Any advice or feedback is very much appreciated.

The Fluent NHibernate example entities are in the Examples.FirstProject.Entities namespace, while you're limiting the AutoMap to FluentExample.Entities (in type => type.Namespace == "FluentExample.Entities").
The first error message points to that by stating "references an unsaved transient instance [...] FluentExample.Entities.Employee"
You should update the AutoMap code to point to the correct interface. If you have classes in multiple interfaces, you can modify the criteria to include an or.

Related

Kotlin exposed - Reference is null

I have two tables: Users and UserPermissions
In the table Users I have an unique id.
In the table UserPermissions I created a reference to the Table Users.
Now when I want to get the UserPermissions from a User, I get a NullPointerException.
I searched around a little bit and found out, that the field permissions of the User is null.
How can this happen?
My code:
User:
object Users : IntIdTable("users") {
val firstName = varchar("first_name", 64)
val lastName = varchar("last_name", 64)
#EntityName("User")
class UserEntity(id: EntityID<Int>) : IntEntity(id) {
companion object : IntEntityClass<UserEntity>(Users)
var firstName by Users.firstName
var lastName by Users.lastName
val permissions by UserPermissionEntity referrersOn UserPermissions.user
}
UserPermission:
object UserPermissions : IntIdTable("user_permissions") {
val user: Column<EntityID<Int>> = reference("user_id", Users)
val permission = integer("permission")
}
class UserPermissionEntity(id: EntityID<Int>) : IntEntity(id) {
companion object : IntEntityClass<UserPermissionEntity>(UserPermissions)
var user by UserEntity referencedOn UserPermissions.user
var permission by UserPermissions.permission
}

How to set alias for nested object in SQL script generated from IQueryable

I have an IQueryable from the database, which I map to view model like this:
IQueryable<ItemList> itemsList = query.Select(x =>
new ItemList()
{
Phone = x.Phone,
Email = x.Email,
Fax = x.Fax,
State = x.StateId.HasValue ? new GenericBox() { Text = x.State.Name , Value = x.State.Id } : null,
Type = x.Type,
ChildItems = x.Contact.ChildItems.OrderBy(a => a.Order).Select(a => new GenericBox() { Text = a.Child.FirstName + " " + a.Child.LastName, Value = a.ChildId })
});
The GenericBox class is like this:
public class GenericBox
{
public string Text { get; set; }
public Guid Value { get; set; }
}
Then I transform this IQueryable to pure SQL and execute it with a SqlCommand.
The problem lies in the properties State and ChildItems.
I need to set alias for State properties Text and Value. Because IQueryable set them in the SQL with random generated names:
SELECT
[Project3].[Id] AS [Id1],
[Project3].[Phone] AS [Phone],
[Project3].[Email] AS [Email],
[Project3].[Fax] AS [Fax],
[Project3].[C2] AS [C2],
[Project3].[Name1] AS [Name1],
[Project3].[StateId] AS [StateId],
[Project3].[Type] AS [Type],
[Project3].[C5] AS [C3],
[Project3].[C3] AS [C4],
[Project3].[AgentId] AS [AgentId]
As you can see in the SELECT Name1 is for the State.Text from my class and C4 is for ChildItem.Text.
I need in the SELECT the alias for column Name1 to be Text for example. And the alias for Column C4 I want to be again Text.

NHibernate Convert query to async query

I'm looking at async-ifying some of our existing code. Unfortunately my experience with NHibernate is lacking. Most of the NHibernate stuff has been easy, considering NHibernate 5 has a lot of support for async. I am, however, stuck.
Originally, we do something like this using our Dependency Injection:
private readonly IRepository repository;
public MovieRepository(IRepository repository)
{
this.repository = repository;
}
public Movie Get(int id)
{
return (from movie in repository.Query<Movie>()
select new Movie
{
ID = movie.ID,
Title = movie.Title,
Genre = new Genre
{
ID = movie.Genre.ID,
Name = movie.Genre.Name,
},
MaleLead = movie.MaleLead,
FemaleLead = movie.FemaleLead,
}).FirstOrDefault();
}
//Repository Query method in Repository.cs
public IQueryable<TEntity> Query<TEntity>() where TEntity : OurEntity
{
session = session.OpenSession();
return from entity in session.Query<TEntity>() select entity;
}
This works great for our current uses. We write things this way to maintain control over our queries, especially related to more complex objects, ensuring we get back exactly what we need.
I've tried a few things, like making the Query method return a Task< List< TEntity>> and using the ToListAsync() method, however because I am returning it as that kind of list I cannot query on it.
I'm sure I've missed something. If anyone can help me out, I would appreciate it.
You need to use FirstOrDefaultAsync in this case.
public async Task<Movie> Get(int id)
{
return await (from movie in repository.Query<Movie>()
select new Movie
{
ID = movie.ID,
Title = movie.Title,
Genre = new Genre
{
ID = movie.Genre.ID,
Name = movie.Genre.Name,
},
MaleLead = movie.MaleLead,
FemaleLead = movie.FemaleLead,
}).FirstOrDefaultAsync();
}
Add this using statement to your file
using NHibernate.Linq;
Then you can change your method to
public async Task<Movie> Get(int id)
{
return await (from movie in repository.Query<Movie>()
select new Movie
{
ID = movie.ID,
Title = movie.Title,
Genre = new Genre
{
ID = movie.Genre.ID,
Name = movie.Genre.Name,
},
MaleLead = movie.MaleLead,
FemaleLead = movie.FemaleLead,
}).FirstOrDefaultAsync();
}
NB: This is only available from NHibernate 5
Addendum:
The code you have in Repository.cs can be simplified to something like this:
//Repository Query method in Repository.cs
public IQueryable<TEntity> Query<TEntity>() where TEntity : OurEntity
{
//session = session.OpenSession(); //this is obviously wrong, but it's beside the point
var session = sessionFactory.OpenSession();
return session.Query<TEntity>(); //the fix
}

lambda query data like sql where not in

in my database i save users tag in table
the table structure is
Table Name : User
Id Name Tags
1 Jack White,Yellow,Green
2 smith Yellow,Green
3 smith Blank
....
the condition is:
string[] tags = {"Yellow","Green"};
I hope can get the data from database,so this is my lambda:
unitOfWork.Repository<User>().find(x=>!x.Any(x.Tag.......);
the sql like:
Select * from Users Where Tags not in('Yellow','Green')
but the tags in database is long string with ","
If you have big data, this is not a good solution But you can after you select all data.
var result = db.Users.ToList()
.Where(i => i.Tags.Split(',').Any(t => tags.Contains(t))).ToList();
I think, normalize your schema looks like better.
Other option:
You can use SqlQuery
class Users
{
public int Id { get; set; }
public string Name { get; set; }
public string Tags { get; set; }
}
string[] tags = {"Yellow","Green"};
var whereClause = String.Join(" OR ", tags.Select(i => String.Format("Tags LIKE %{0}%", i));
var query = String.Format(#"
SELECT
*
FROM
Users
Where
{0}
", whereClause);
var result = dbContext.Database.SqlQuery<Users>(query);
Query looks like:
SELECT
*
FROM
Users
Where
Tags LIKE %Yellow% OR Tags LIKE %Green%

Generate form from database in MVC

I am trying to generate form from my database.
CREATE TABLE [dbo].[FieldsMaster](
[FieldId] [int] IDENTITY(1,1) NOT NULL,
[FieldControlName] [varchar](50) NULL,
[FieldDataType] [varchar](20) NULL,
[FieldControlType] [varchar](30) NULL,
[DisplayLabel] [varchar](200) NULL,
[FieldSize] [int] NULL,
[FieldRegularExpression] [varchar](200) NULL,
[FieldOptions] [varchar](500) NULL,
[OptionalQuery] [varchar](200) NULL,
[REMessage] [varchar](150) NULL,
[FieldRequired] [bit] NULL,
[FRMessage] [varchar](150) NULL
)
Generate some data for the table
insert into FieldsMaster (FieldControlName,FieldDataType,FieldControlType,DisplayLabel,FieldSize,FieldRegularExpression,
FieldOptions,OptionalQuery,REMessage,FieldRequired,FRMessage,IsActive)
values
('txtOtherInfo','varchar','TextArea','Other Information',400,NULL,
NULL,NULL,NULL,0,NULL)
insert into FieldsMaster (FieldControlName,FieldDataType,FieldControlType,DisplayLabel,FieldSize,FieldRegularExpression,
FieldOptions,OptionalQuery,REMessage,FieldRequired,FRMessage,IsActive)
values
('txtTitle','varchar','TextBox','Title',100,NUll,
NULL,NULL,NULL,1,'Please enter title')
Now this form with it fields is stored in my sql db. I want to generate a form in mvc. How the model should be formed/ how to generate form in view?
I am really confused here. Your help is really appreciated. Thanks
To have more idea, below form should be displayed based on the fields in FieldsMaster
Other Information(as label) : TextArea (With Id as txtOtherInfo)
Title (as Label) : TextBox (With Id as txtTitle)
If you want to add form directly from database, you can do.
First you need to do into model an Enum like these (for email):
public int EmailTemplateId { get; set; }
public int Type { get; set; }
public string Name { get; set; }
public enum Emailtype
{
Base = 0,
Recovery = 1,
NewAccount = 2,
ChangePassword = 3,
BlockAccount = 4,
UnlockAccount = 5,
ForgetPassword = 6
}
So each one of thee represent a different template, and in your template view you have something like
<body>
//some code of your template
{-container-}
</body>
As you can see {-container-} is the property you change for each template. so you made new containers that you´be insert into sql like
<tr>
<td>Hi {name}. Your password is {password}</td>
</tr>
You don´t need tag here because you have it into your first template and this code
And in controller:
public void NewAccount(string name, string email,string password, string user)
{
var from = model.From;
var loginUrl = model.LoginUrl;
const string title = "New Register - Stackoverflow";
EmailsService sendEmail = new EmailsService
{
Subject = title,
To = email,
From = from
};
}
//There is our first template (Base template)
var templateBase = Get(Emailtype.Base);
//This one is template who changes (container)
var templateText = Get(Emailtype.NewAccount);
//Here you replace Name property of class for your container code
var body = templateBase.Name.Replace("{-container-}", templateText.Name);
sendEmail.EmailBody = body.Replace("{Name}", name)
.Replace("{Title}", title)
.Replace("{User}", user)
.Replace("{Password}", password)
.Replace("{Link}", loginUrl);
sendEmail.Send();
}
Finally in your sql you can insert code of your container... it show like that:
EmailTemplateId=1
Type= 1 //(Recovery ones)
Name= <tr> <td>Hi {name}. Your password is {password}</td> </tr>
Hope it helps!

Resources