fluentnhibernate hasmanytomany same identifier exception - nhibernate

I have a many-to-many relationship between two objects (Application, Query). I have constructed the map to have a HasManyToMany mapping in both object maps.
The first time I use the SaveOrUpdate the application, it works fine, and the entry is placed correctly in the join table.
However, the second time I use it, I get the error: 'a different object with the same identifier was already associated with the session'.
The exception is thrown in the last couple of lines of the addQuery code shown below.
Here are the entities and the maps. Any suggestions would be greatly appreciated.
public class Application
{
public virtual int id { get; set; }
public virtual string name { get; set; }
public virtual IList<Query> queries { get; set; }
public Application()
{
this.queries = new List<Query>();
}
public virtual void AddQuery(Query qry)
{
qry.applicationsUsedIn.Add(this);
queries.Add(qry);
}
}
public class Query
{
public virtual int id { get; protected set; }
public virtual string name { get; set; }
public virtual string query { get; set; }
public virtual IList<QueryParameters> parameters { get; set; }
public virtual IList<Application> applicationsUsedIn { get; set; }
public Query()
{
this.parameters = new List<QueryParameters>();
this.applicationsUsedIn = new List<Application>();
}
public virtual void AddParameter(QueryParameters qp)
{
qp.query = this;
this.parameters.Add(qp);
}
}
public class ApplicationMap : ClassMap<Application>
{
public ApplicationMap()
{
Table("dbo.Applications");
Id(x => x.id).Column("id");
Map(x => x.name).Column("name");
HasManyToMany(x => x.queries)
.Table("dbo.ApplicationsQueries")
.ParentKeyColumn("appid")
.ChildKeyColumn("qryid")
.Not.LazyLoad()
.Cascade.SaveUpdate();
}
}
public class QueryMap : ClassMap<Query>
{
public QueryMap()
{
Table("dbo.Queries");
Id(x => x.id);
Map(x => x.name);
Map(x => x.query);
HasMany(x => x.parameters)
.Cascade.All()
.Inverse();
HasManyToMany(x => x.applicationsUsedIn)
.Table("dbo.ApplicationsQueries")
.ParentKeyColumn("qryid")
.ChildKeyColumn("appid")
.Inverse()
.Cascade.SaveUpdate()
.Not.LazyLoad();
}
}
public void addQuery(string appname, string qryname, string qrystr)
{
Application app = getApplication(appname);
if (null == app)
{
app = addApplication(appname);
}
Query qry = getQuery(appname, qryname);
if (null == qry)
{
using (ISessionFactory isf = getSessionFactory())
{
using (var sess = isf.OpenSession())
{
using (var tran = sess.Transaction)
{
tran.Begin();
qry = new Query();
qry.name = qryname;
qry.query = qrystr;
sess.Save(qry);
tran.Commit();
}
}
}
}
if (!app.queries.Contains(qry))
{
using (ISessionFactory isf = getSessionFactory())
{
using (var sess = isf.OpenSession())
{
using (var tran = sess.Transaction)
{
tran.Begin();
app.AddQuery(qry);
//This is where the exception is thrown
sess.SaveOrUpdate(app);
tran.Commit();
}
}
}
}
}
UPDATED CODE in case it helps someone else
public ApplicationMap()
{
Table("dbo.Applications");
Id(x => x.id).Column("id");
Map(x => x.name).Column("name");
HasManyToMany(x => x.queries)
.Table("dbo.ApplicationsQueries")
.ParentKeyColumn("appid")
.ChildKeyColumn("qryid")
.LazyLoad();
}
public QueryMap()
{
Table("dbo.Queries");
Id(x => x.id);
Map(x => x.name);
Map(x => x.query);
HasMany(x => x.parameters)
.Cascade.All()
.Inverse();
HasManyToMany(x => x.applicationsUsedIn)
.Table("dbo.ApplicationsQueries")
.ParentKeyColumn("qryid")
.ChildKeyColumn("appid")
.Inverse()
.LazyLoad();
}
public void addQuery(string appname, string qryname, string qrystr)
{
using (ISessionFactory isf = getSessionFactory())
{
using (var sess = isf.OpenSession())
{
using (var tran = sess.Transaction)
{
tran.Begin();
var critapp = sess.CreateCriteria<Application>()
.Add(Restrictions.Eq("name", appname));
Application app = (Application)critapp.UniqueResult();
if (null == app)
{
app = new Application();
app.name = appname;
sess.Save(app);
}
var critqry = sess.CreateCriteria<Query>()
.Add(Restrictions.Eq("name", qryname));
Query qry = (Query)critqry.UniqueResult();
if (null == qry)
{
qry = new Query();
qry.name = qryname;
qry.query = qrystr;
sess.Save(qry);
}
if (!app.queries.Contains(qry))
{
app.AddQuery(qry);
}
tran.Commit();
}
}
}
}

The problem here is hidden in many opened sessions for (in fact) one operation. This is not the correct way how to execute this insert/updates. We should always wrap a set of operations relying on each other, into ONE session, one transaction.
So what happened is that here we've got the Query recieved like this:
Query qry = getQuery(appname, qryname);
We have an object, which is (was) part of the session, which just ran out of the scope. The qry instance is fully populated now because
it is an existing object (loaded from DB)...
the mapping of the collection IList<Application> applicationsUsedIn (see your mapping) is .Not.LazyLoad()
and the same is true for other Not.LazyLoad() mappings...
So once we come to the last transaction (and its own session) ... our objects could be deeply populated... having the same IDs as loaded objects inside of that last session
To solve the issue quickly:
Open the session at the begining of the operation
Open the transaction at the begining
Call Save() only, if we do have new object
For objects retrieved via getQuery(), getApplication() (beeing in the same session) DO NOT call the SaveOrUpdate(). They are already in the session, and that's what the SaveOrUpdated in this case mostly does (put them in the session)
a) Call the transaction.Commit() and all the stuff will be properly persisted
b) Close the session at the end of operation
Note: I would change the mapping of your many-to-many
remove the Not.LazyLoad(). Lazy is what we mostly want..
remove Cascade because it is about the other end not about the pairing table. If this was intended then leave it

Related

Nhibernate Remove child collection without having property in the parent object

Suppose I have the following model
public class Customer
{
public virtual Guid Id { get; set; }
public virtual string Name { get; set; }
}
public class ActivityLog
{
public virtual Guid Id { get; set; }
public virtual Guid CustomerId { get; set; }
public virtual Customer Customer { get; set; }
public virtual DateTime ActivityDate { get; set; }
}
I would like to be able to remove customer and all corresponding ActivityLog items, by calling
session.Delete(customer);
What I don't want to is to have a property
List<ActivityLog> Logs in my Customer class. Is it possible to achieve in Nhibernate? I have tried EF, and it works there, but in HN getting reference constraint exception.
My mappings:
public class CustomerMap : ClassMapping<Customer>
{
public CustomerMap()
{
Id(x => x.Id, map => map.Generator(Generators.GuidComb));
Property(x => x.Name);
}
}
public class ActivityLogMap : ClassMapping<ActivityLog>
{
public ActivityLogMap()
{
Id(x => x.Id, map => map.Generator(Generators.GuidComb));
Property(x => x.ActivityDate);
ManyToOne(x => x.Customer, mapping =>
{
mapping.Class(typeof(Customer));
mapping.Column("CustomerId");
});
}
}
Maybe possible to have some extension hook and inspect mapping and do it manually for Nhibernate?
Edit: Here how it works with EF
public class CustomerEFMap : EntityTypeConfiguration<Customer>
{
public CustomerEFMap()
{
ToTable("Customer");
HasKey(x => x.Id);
Property(x => x.Name);
}
}
public class ActivityLogEFMap : EntityTypeConfiguration<ActivityLog>
{
public ActivityLogEFMap()
{
ToTable("ActivityLog");
HasKey(x => x.Id);
HasRequired(x => x.Customer).WithMany().HasForeignKey(x => x.CustomerId);
}
}
using (var context = new ObjectContext())
{
var customer = context.Set<Customer>().Find(id);
context.Set<Customer>().Remove(customer);
context.SaveChanges();
}
Having Customer and corresponding ActivityLog in DB, removes both
I would like to be able to remove customer and all corresponding
ActivityLog items, by calling
session.Delete(customer);
What I don't want to is to have a property List Logs in
my Customer class. Is it possible to achieve in Nhibernate?
NO. Impossible, not intended, not supported. NHibernate is ORM tool and will/can care about relations. Without relations, no care (no cascading)
But, we can always hide that List Property by making it protected
public class Customer
{
public virtual Guid Id { get; set; }
public virtual string Name { get; set; }
// HIDDEN in fact from consumers, managed by NHibernate
protected virtual IList<ActivitLog> { get; set; }
}
and the mapping with cascade in place - will do what is required.
As Radim Köhler states, I don't think there's any simple way to map the behaviour of a cascade without actually having the relationship. But as your reason for this is a plugin-based architecture, making use of a partial class might be what you need.
You can include the collection of ActivityLogs as a protected collection as part of a partial class in the plugin DLL. If your mapping then maps the collection, deleting the Customer will delete the ActivityLogs.
The following example should work - note that I'm using FluentNhibernate for the mapping.
This solution does rely on you be able to mark the Customer class as partial.
using FluentAssertions;
using FluentNHibernate;
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using FluentNHibernate.Mapping;
using NHibernate.Linq;
using NHibernate.Tool.hbm2ddl;
using NUnit.Framework;
using System;
using System.Collections.Generic;
namespace MapTest
{
public partial class Customer
{
public virtual Guid Id { get; set; }
public virtual string Name { get; set; }
}
public class ActivityLog
{
public virtual Guid Id { get; set; }
public virtual Customer Customer { get; set; }
public virtual DateTime ActivityDate { get; set; }
}
public class CustomerMap : ClassMap<Customer>
{
public CustomerMap()
{
Id(x => x.Id).GeneratedBy.Guid();
Map(x => x.Name);
HasMany<ActivityLog>(Reveal.Member<Customer>("ActivityLogs")).Cascade.All();
}
}
public class ActivityLogMap : ClassMap<ActivityLog>
{
public ActivityLogMap()
{
Id(x => x.Id).GeneratedBy.Guid();
Map(x => x.ActivityDate);
References(x => x.Customer);
}
}
// Part of your plugin DLL
public partial class Customer
{
protected virtual IList<ActivityLog> ActivityLogs { get; set; }
}
[TestFixture]
public class PartialClassCascade
{
[Test]
public void RunOnceToSetupDb()
{
Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2012.ConnectionString(#"Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=MapTest;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False"))
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<CustomerMap>())
.ExposeConfiguration(cfg => new SchemaUpdate(cfg).Execute(false, true))
.BuildSessionFactory();
}
[Test]
public void DeletingCustomerWithActivityLogs()
{
var sessionFactory = Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2012.ConnectionString(#"Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=MapTest;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False"))
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<CustomerMap>())
.BuildSessionFactory();
using (var session = sessionFactory.OpenSession())
using (var tx = session.BeginTransaction())
{
session.CreateQuery("delete ActivityLog a").ExecuteUpdate();
session.CreateQuery("delete Customer c").ExecuteUpdate();
tx.Commit();
}
var homerId = default(Guid);
using (var session = sessionFactory.OpenSession())
using (var tx = session.BeginTransaction())
{
var homer = new Customer
{
Name = "Homer Simpson"
};
var monty = new Customer
{
Name = "Monty Burns"
};
session.Save(homer);
session.Save(monty);
homerId = homer.Id;
var activityLog1 = new ActivityLog
{
Customer = homer,
ActivityDate = DateTime.Now,
};
var activityLog2 = new ActivityLog
{
Customer = monty,
ActivityDate = DateTime.Now.AddDays(1),
};
session.Save(activityLog1);
session.Save(activityLog2);
tx.Commit();
}
using (var session = sessionFactory.OpenSession())
using (var tx = session.BeginTransaction())
{
var customer = session.Get<Customer>(homerId);
session.Delete(customer);
tx.Commit();
}
using (var session = sessionFactory.OpenSession())
using (var tx = session.BeginTransaction())
{
var customers = session.Query<Customer>();
var activityLogs = session.Query<ActivityLog>();
customers.Should().HaveCount(1);
activityLogs.Should().HaveCount(1);
}
}
}
}

Basic Fluent NHibernate relationship issue

The project that I am working on at the moment is using Entity Framework, however there are some issues that we have come across and therefore I am researching using NHibernate which we believe will sort out the majority of issues we have.
Anyway, I have been replicating a simple part of the system, but I have ran into what I assume is a very simple problem with a one-to-many relationship as it is giving very strange results.
Here are my entities:
public class Task : Base.Domain
{
private IList<TaskProperty> _taskProperties = new BindingList<taskProperty>();
private string _name = String.Empty;
private string _description = String.Empty;
public virtual IList<TaskProperty> TaskProperties
{
get
{
return _taskProperties;
}
set
{
if (_taskProperties == value) return;
_taskProperties = value;
OnNotifiyPropertyChanged("TaskProperties");
}
}
public virtual string Name
{
get
{
return _name;
}
set
{
if (_name == value) return;
_name = value;
base.OnNotifiyPropertyChanged("Name");
}
}
public virtual string Description
{
get
{
return _description;
}
set
{
if (_description == value) return;
_description = value;
base.OnNotifiyPropertyChanged("Description");
}
}
public Task()
: base()
{ }
}
public class TaskProperty : Base.Domain
{
private Task _task = null;
private string _name = string.Empty;
private string _description = string.Empty;
private int _propertyType = 0;
//public virtual int TaskID { get; set; }
public virtual Task Task
{
get
{
return _task;
}
set
{
if (_task == value) return;
_task = value;
OnNotifiyPropertyChanged("Task");
}
}
public virtual string Name
{
get
{
return _name;
}
set
{
if (_name == value) return;
_name = value;
OnNotifiyPropertyChanged("Name");
}
}
public virtual string Description
{
get
{
return _description;
}
set
{
if (_description == value) return;
_description = value;
OnNotifiyPropertyChanged("Description");
}
}
public virtual int PropertyType
{
get
{
return _propertyType;
}
set
{
if (_propertyType == value) return;
_propertyType = value;
OnNotifiyPropertyChanged("PropertyType");
}
}
public TaskProperty()
: base()
{ }
}
Here are my NHibernate mappings:
public class TaskMapping : ClassMap<Task>
{
public TaskMapping()
{
Id(x => x.Id).Column("RETTaskID");
Map(x => x.Name);
Map(x => x.Description);
Map(x => x.Version);
HasMany(x => x.TaskProperties).KeyColumn("RETTaskPropertyID");
Table("RETTask");
}
}
public class TaskPropertyMapping : ClassMap<TaskProperty>
{
public TaskPropertyMapping()
{
Id(x => x.Id).Column("RETTaskPropertyID");
Map(x => x.Name);
Map(x => x.Description);
Map(x => x.PropertyType);
References(x => x.Task).Column("RETTaskID");
Table("RETTaskProperty");
}
}
Note: The Domain class which these entities inherit from holds the ID (int Id).
The problem that I am facing is that when I get I Task from the database with an ID of 27 for example, I get the TaskProperty with an ID of 27 as well, not the expected 4 TaskProperties that are related to the Task via a foreign key.
This worked fine in Entity Framework and I know this is a simple situation for any ORM, so I assume I have set up my mappings incorrectly, but from all the examples I have found, I don't seem to be doing anything wrong!
Any answers/suggestions will be most welcome. Thanks.
You are almost there. The Column mapping for HasMany and References must be the same:
public TaskMapping()
{
...
HasMany(x => x.TaskProperties).KeyColumn("RETTaskID"); // use this
// HasMany(x => x.TaskProperties).KeyColumn("RETTaskPropertyID"); // instead of this
}
public TaskPropertyMapping()
{
...
References(x => x.Task).Column("RETTaskID");
}
The collection item has to have a reference column to the owner. This column is used for both directions, because that's how the reference in DB managed...

fluentnhibernate configuration Error

I have created one console application by watching videos from http://www.d80.co.uk/post/2011/10/06/NHibernate-Video-Tutorial.aspx website. when i tried to executing the code its giving me following error:
An invalid or incomplete configuration was used while creating a SessionFactory. Check PotentialReasons collection, and InnerException for more detail.
but when i have downloaded the code and executed, its working fine. i have checked both the code and are same. so not under stand what i am doing wrong. i am posting my code here please help me to get out of this situation.
NhibernateHelper.cs
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using NHibernate;
using NHibernate.Tool.hbm2ddl;
using System;
namespace FluentNHibernate
{
class NhibernateHelper
{
private static ISessionFactory _sessionFactory;
private static ISessionFactory sessionFactory
{
get
{
if (_sessionFactory == null)
{
initialisationFactory();
}
return _sessionFactory;
}
}
private static void initialisationFactory()
{
try
{
_sessionFactory = Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2005.ConnectionString(#"Server=10.10.10.7;Database=TestDatabase;uid=sa;pwd=9ijnhy6;Trusted_Connection=false;").ShowSql())
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<Car>())
.ExposeConfiguration(cfg => new SchemaExport(cfg).Create(true, true))
.BuildSessionFactory();
}
catch (Exception e)
{
throw;
}
}
public static ISession OpenSession()
{
return sessionFactory.OpenSession();
}
}
}
Program.cs
using System;
using FluentNHibernate.Mapping;
namespace FluentNHibernate
{
internal class Program
{
public static void Main(string[] args)
{
using (var session = NhibernateHelper.OpenSession())
{
using (var transaction = session.BeginTransaction())
{
var fordMake = new Make
{
Name = "Ford"
};
var fiestaModel = new Model
{
Name = "Fiesta",
Make = fordMake
};
var car = new Car
{
Make = fordMake,
Model = fiestaModel,
Title = "Dans Car"
};
session.Save(car);
transaction.Commit();
Console.WriteLine("Created Car " + car.Title);
}
}
Console.ReadLine();
}
}
public class MakeMap : ClassMap<Make>
{
public MakeMap()
{
Id(x => x.Id);
Map(x => x.Name);
}
}
public class ModelMap : ClassMap<Model>
{
public ModelMap()
{
Id(x => x.Id);
Map(x => x.Name);
References(x => x.Make).Cascade.All();
}
}
public class CarMap : ClassMap<Car>
{
public CarMap()
{
Id(x => x.Id).GeneratedBy.HiLo("Car");
Map(x => x.Title);
References(x => x.Make).Cascade.All();
References(x => x.Model).Cascade.All();
}
}
public class Make
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
}
public class Model
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual Make Make { get; set; }
}
public class Car
{
public virtual int Id { get; set; }
public virtual string Title { get; set; }
public virtual Make Make { get; set; }
public virtual Model Model { get; set; }
}
}
Your NHibernateHelper.cs is considerably different than mine.
Try changing
_sessionFactory = Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2005.ConnectionString(#"Server=10.10.10.7;Database=TestDatabase;uid=sa;pwd=9ijnhy6;Trusted_Connection=false;").ShowSql())
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<Car>())
.ExposeConfiguration(cfg => new SchemaExport(cfg).Create(true, true))
.BuildSessionFactory();
To:
_sessionFactory = Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2005.ConnectionString(c => c.FromConnectionStringWithKey("ConnectionString")))
.Mappings(cfg =>
{
cfg.FluentMappings.AddFromAssembly(Assembly.GetExecutingAssembly());
cfg.FluentMappings.Conventions.Add(AutoImport.Never());
})
.ExposeConfiguration(x =>
{
x.SetProperty("current_session_context_class", mode);
})
.BuildSessionFactory();
In Your web.config or app.config add the following within tags:
<connectionStrings>
<add name="ConnectionString" connectionString="Data Source=10.10.10.7; Initial Catalog=TestDatabase; User Id=sa; Password=9ijnhy6;"/>
</connectionStrings
Hopefully this helps.

Fluent NHibernate compositeid to mapped class

I'm trying to figure out how to use CompositeId to map another class. Here's a test case:
The tables:
TestParent:
TestParentId (PK)
FavoriteColor
TestChild:
TestParentId (PK)
ChildName (PK)
Age
The classes in C#:
public class TestParent
{
public TestParent()
{
TestChildList = new List<TestChild>();
}
public virtual int TestParentId { get; set; }
public virtual string FavoriteColor { get; set; }
public virtual IList<TestChild> TestChildList { get; set; }
}
public class TestChild
{
public virtual TestParent Parent { get; set; }
public virtual string ChildName { get; set; }
public virtual int Age { get; set; }
public override int GetHashCode()
{
return Parent.GetHashCode() ^ ChildName.GetHashCode();
}
public override bool Equals(object obj)
{
if (obj is TestChild)
{
var toCompare = obj as TestChild;
return this.GetHashCode() != toCompare.GetHashCode();
}
return false;
}
}
The Fluent NHibernate maps:
public class TestParentMap : ClassMap<TestParent>
{
public TestParentMap()
{
Table("TestParent");
Id(x => x.TestParentId).Column("TestParentId").GeneratedBy.Native();
Map(x => x.FavoriteColor);
HasMany(x => x.TestChildList).KeyColumn("TestParentId").Inverse().Cascade.None();
}
}
public class TestChildMap : ClassMap<TestChild>
{
public TestChildMap()
{
Table("TestChild");
CompositeId()
.KeyProperty(x => x.ChildName, "ChildName")
.KeyReference(x => x.Parent, "TestParentId");
Map(x => x.Age);
References(x => x.Parent, "TestParentId"); /** breaks insert **/
}
}
When I try to add a new record, I get this error:
System.ArgumentOutOfRangeException :
Index was out of range. Must be
non-negative and less than the size of
the collection. Parameter name: index
I know this error is due to the TestParentId column being mapped in the CompositeId and References calls. However, removing the References call causes another error when querying TestChild based on the TestParentId.
Here's the code that does the queries:
var session = _sessionBuilder.GetSession();
using (var tx = session.BeginTransaction())
{
// create parent
var p = new TestParent() { FavoriteColor = "Red" };
session.Save(p);
// creat child
var c = new TestChild()
{
ChildName = "First child",
Parent = p,
Age = 4
};
session.Save(c); // breaks with References call in TestChildMap
tx.Commit();
}
// breaks without the References call in TestChildMap
var children = _sessionBuilder.GetSession().CreateCriteria<TestChild>()
.CreateAlias("Parent", "p")
.Add(Restrictions.Eq("p.TestParentId", 1))
.List<TestChild>();
Any ideas on how to create a composite key for this scenario?
I found a better solution that will allow querying and inserting. The key is updating the map for TestChild to not insert records. The new map is:
public class TestChildMap : ClassMap<TestChild>
{
public TestChildMap()
{
Table("TestChild");
CompositeId()
.KeyProperty(x => x.ChildName, "ChildName")
.KeyReference(x => x.Parent, "TestParentId");
Map(x => x.Age);
References(x => x.Parent, "TestParentId")
.Not.Insert(); // will avoid "Index was out of range" error on insert
}
}
Any reason you can't modify your query to just be
_sessionBuilder.GetSession().CreateCriteria<TestChild>()
.Add(Restrictions.Eq("Parent.TestParentId", 1))
.List<TestChild>()
Then get rid of the reference?

fluent-nhibernate: not getting the records

I have an entity like
public class SKU
{
//public int Id { get; set; }
public string FactoruCode { get; set; }
public string Ptoduct { get; set; }
}
and mapping defined as
public class SKUMap : ClassMap<SKU>
{
public SKUMap()
{
Table("MST_PRODUCT");
Not.LazyLoad();
Id(x => x.Ptoduct).GeneratedBy.Assigned();
Map(x => x.Ptoduct, "PRODUCT_NAME");
Map(x => x.FactoruCode, "FACTORY_CODE");
}
}
and retrieving the records like
class Program
{
static void Main()
{
var sessionFactory = CreateSessionFactory();
using (var session = sessionFactory.OpenSession())
{
using (session.BeginTransaction())
{
var skus = session.CreateCriteria(typeof(SKU)).List<SKU>();
foreach (var sku in skus)
{
Console.WriteLine(sku.Ptoduct);
}
}
}
}
private static ISessionFactory CreateSessionFactory()
{
var cfg = OracleClientConfiguration.Oracle10
.ConnectionString(c =>
c.Is(
#"DATA SOURCE=SERVER_NAME;PERSIST SECURITYINFO=True;USER ID=USER_ID;Password=PWD"));
return Fluently.Configure()
.Database(cfg).Mappings(m => m.FluentMappings.AddFromAssemblyOf<Program>())
.ExposeConfiguration(BuildSchema).BuildSessionFactory();
}
private static void BuildSchema(NHibernate.Cfg.Configuration config)
{
new SchemaExport(config).Create(false, true);
}
}
but the table has more columns than specified for entity. This code executes well, but I'm not able to get the list of SKUs (table has more than 8000 rows).
Please help me to understand the problem.
Your SKU map is wrong. Why have you defined PRODUCT_NAME as an Id column? You need to fix it by setting the Id to an Id column (which you have commented out):
Id(x => x.Id, "NAME_OF_YOUR_ID_COLUMN_HERE").GeneratedBy.Assigned();
Map(x => x.Ptoduct, "PRODUCT_NAME");
If PRODUCT_NAME is indeed the Id, you need to set it like this:
Id(x => x.Ptoduct, "PRODUCT_NAME").GeneratedBy.Assigned();
and remove the other line:
Map(x => x.Ptoduct, "PRODUCT_NAME");
Also, if your database has more fields or tables then you are mapping, it can give you many errors. To resolve them, you need to set use_proxy_validator to false in your configuration.
EDIT:
NHibernate requires an Id column to work properly. I don't even know that if it does work without actually having a column declared as an Id column. Even if you declare Ptoduct as an Id column, you will not be able to properly query the database as querying for any of all objects with the same Ptoduct will return the topmost object.