How is a Fluent Nhibernate Reference / HasMany relationship supposed to work? - nhibernate

I have two tables setup with a reference and hasmany relationship. When the Xref.SaveOrUpdate() is called an "Invalid index 7 for this SqlParameterCollection with Count=7." exception is thrown. I get the feeling I'm not setting up the HasMany and References correctly. What should I be doing differently?
public class PortalPhysicianMap : ClassMap<PortalPhysician>
{
public PortalPhysicianMap()
{
Table("PortalPhysicians");
Id(x => x.PhysicianRno).GeneratedBy.Identity();
Map(x => x.A1PhysicianRno);
Map(x => x.LastName);
Map(x => x.FirstName);
Map(x => x.TitleName);
Map(x => x.SuffixName);
Map(x => x.CorrName);
Map(x => x.Specialty);
Map(x => x.Institution);
Map(x => x.Addr1);
Map(x => x.Addr2);
Map(x => x.City);
Map(x => x.State);
Map(x => x.PostalCode);
Map(x => x.Country);
Map(x => x.Phone);
Map(x => x.Fax);
Map(x => x.InactiveDt);
Map(x => x.CreatedDate, "CreatedDt");
Map(x => x.UpdatedDate, "UpdatedDt");
HasMany(x => x.Xrefs)
.KeyColumn("A1PhysicianRno");
//.Cascade.All();
}
}
public class PortalLoginPhyXrefMap : ClassMap<PortalLoginPhyXref>
{
public PortalLoginPhyXrefMap()
{
Table("PortalLoginPhyXref");
Id(x => x.XrefRno).GeneratedBy.Identity();
Map(x => x.LoginRno);
Map(x => x.A1PhysicianRno);
Map(x => x.UserName);
Map(x => x.UserRole);
Map(x => x.InactiveDt);
Map(x => x.CreatedDate, "CreatedDt");
Map(x => x.UpdatedDate, "UpdatedDt");
References<PortalPhysician>(x => x.Login)
.Column("LoginRno");
}
}
using (ISession s = Env.dbPortal.OpenSession())
{
try
{
using (ITransaction Trans = s.BeginTransaction())
{
Trans.Begin();
foreach (PortalLogin Login in lstLogins)
{
if (Login.UserName != null)
{
Login.SaveOrUpdate(s);
foreach (PortalLoginPhyXref Xref in Login.Xrefs)
{
Xref.LoginRno = Login.LoginRno;
Xref.SaveOrUpdate(s);
}
}
}
Trans.Commit();
}
}
catch (Exception Ex)
{
frmError.Show(Ex);
}
}
Additional code showing what happens in the SaveOrUpdate()
public class PortalLoginPhyXref : BaseRec
{
public virtual void SaveOrUpdate(ISession Sess)
{
base.SaveOrUpdate(Sess, XrefRno);
}
}
public abstract class BaseRec
{
public virtual DateTime CreatedDate { get; set; }
public virtual string CreatedUserID { get; set; }
public virtual DateTime? UpdatedDate { get; set; }
public virtual string UpdatedUserID { get; set; }
public virtual void SaveOrUpdate(ISession Sess, int Rno)
{
SaveOrUpdate(Sess, (Rno == 0));
}
public virtual void SaveOrUpdate(ISession Sess, string ID)
{
SaveOrUpdate(Sess, (ID == null));
}
private void SaveOrUpdate(ISession Sess, bool Save)
{
if (Save)
{
CreatedDate = DateTime.Now;
CreatedUserID = Env.UserID;
}
UpdatedDate = DateTime.Now;
UpdatedUserID = Env.UserID;
Sess.SaveOrUpdate(this);
}
}

You are mapping the same column twice in your mapping above. That is what generally causes the Invalid index 7 for this SqlParameterCollection with Count=7 error.
Here is an example of where you are doing this:
Map(x => x.LoginRno);
References<PortalPhysician>(x => x.Login)
.Column("LoginRno");
You should not be doing Map(x => x.LoginRno)

Login.SaveOrUpdate(s); // save or update transient login object with all referenced objects
foreach (PortalLoginPhyXref Xref in Login.Xrefs)
{
Xref.LoginRno = Login.LoginRno;
// Xref.SaveOrUpdate(s); // They'll update when you close transaction.
}

Related

Fluent Nhibernate: Mapping Issue

I am very much new to Fluent Nhibernate. I am stuck with the one situation.
Please find bellow details about it.
Our table structure is like as
Table Student { Student_Id, Name}
Table School { School_Id, Name}
Table LinkTable { School_Id, Student_Id}
LinkTable contains only id of the Student and School. [Composite Key]
Relation is like
1) One student can be part of 0 or 1 School.
2) One School can contains many students.
Can anyone please let me know how the mapping will be done for each file?
or let mw know what is wrong in following mapping files
Right now, it is giving me error that Student Property is not found on SchoolStudent.
public Student()
{
Id(x => x.Id);
Map(x => x.Name);
HasOne(x => x.SchoolStudent).PropertyRef(r => r.Student);
}
public School()
{
Id(x => x.Id);
Map(x => x.Name);
HasMany(x => x.SchoolStudent).KeyColumn("School_Id").Inverse().Cascade.AllDeleteOrphan();
}
public SchoolStudent()
{
CompositeId().KeyReference(x => x.School, "School_Id")
.KeyReference(x => x.Student, "Student_Id");
}
Thanks,
Mahesh
I would re-write it to something like this:
Student.cs
public class Student
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual IList<School> Schools { get; set; }
public Student()
{
Schools = new List<School>();
}
}
School.cs
public class School
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual IList<Student> Students { get; set; }
public School()
{
Students = new List<Student>();
}
}
StudentMap.cs
public class StudentMap : ClassMap<Student>
{
public Student()
{
Id(x => x.Id , "Student_Id");
Map(x => x.Name , "Name");
HasManyToMany(x => x.Schools).Table("LinkTable")
.ParentKeyColumn("Student_Id")
.ChildKeyColumn("School_Id");
}
}
SchoolMap.cs
public class SchoolMap: ClassMap<School>
{
public School()
{
Id(x => x.Id , "School_Id");
Map(x => x.Name , "Name");
HasManyToMany(x => x.Students).Table("LinkTable")
.ParentKeyColumn("School_Id")
.ChildKeyColumn("Student_Id");
}
}
If a student can only be associated with 0 or 1 schools, then you might consider dropping the LinkTable and the SchoolStudent class and just add School_Id to the Student table and a reference to School in the Student class.
Then your mappings are like:
public Student()
{
Id(x => x.Id);
Map(x => x.Name);
References(x => x.School);
}
public School()
{
Id(x => x.Id);
Map(x => x.Name);
HasMany(x => x.Student).Inverse().Cascade.AllDeleteOrphan();
}

Nhibernate Component Mapping : Parent Object null in Value Object while querying from database

I am mapping my value Object Item as component withthe folowing mapping configuration
{
Table("Product");
Not.LazyLoad();
Id(x => x.Id, "id");
Map(x => x.Number, "number");
Map(x => x.Name, "name");
Map(x => x.Description, "description");
Map(x => x.Status, "status");
HasMany(x => x.ItemLines).Component(
m =>
{
m.Map(x => x.ItemId, "itemid");
m.Map(x => x.Qty, "quantity");
}).Table("productitems").KeyColumn("itemid");
}
Class structure
public class ItemLine
{
public Product Product { get; set; }
public Guid ItemId { get; set; }
public int Qty { get; set; }
public ItemLine()
{
}
public ItemLine(Product product, Guid itemId, int qty)
{
Product = product;
ItemId = itemId;
Qty = qty;
}
//Equality and GetHashCode implemented.....
}
I am able to insert data to Database but while retrieving back by Product Id, the Product property in Item Line is null.
Do I need to pass any References in Mapping>
Please help
Thank you,
Mar
Ok. Solved by trial and error.
Add m.ParentReference(x => x.Product);
{
Table("Product");
Not.LazyLoad();
Id(x => x.Id, "id");
Map(x => x.Number, "number");
Map(x => x.Name, "name");
Map(x => x.Description, "description");
Map(x => x.Status, "status");
HasMany(x => x.ItemLines).Component(
m =>
{
m.Map(x => x.ItemId, "itemid");
m.Map(x => x.Qty, "quantity");
m.ParentReference(x => x.Product);
}).Table("productitems").KeyColumn("itemid");
}
hope this helps someone.

Fluent Nhibernate Many-to-Many mapping with extra column

I want to map sth like this using fluent Nhibernate but I am not sure how to map the inventory table
This is the tables I have :
Product (Id,Name, ...)
Warehouse(Id, Name, ...)
Inventory(Product_id, Warehouse_id, StockInHand)
and Mappings like below
Public ProductMap()
{
Id(x => x.Id);
Map(x => x.Name);
HasManyToMany(x => x.StoresStockedIn)
.Cascade.All()
.Inverse()
.Table("Inventory");
}
public WarehouseMap()
{
Id(x => x.Id);
Map(x => x.Name);
HasManyToMany(x => x.Products)
.Cascade.All()
.Table("Inventory");
}
The problem I face is that how can I map the StockInHand (how should the inventory model mapping?).
or are there other way to model this scenario ?
I have read some existing questions but not yet get clear understand what to do.
Thanks
Your relationship is not a many-to-many as far as NHibernate is concerned. A true many-to-many has no additional columns, such as StockInHand in your example.
You have to map this as two one-to-many relationships, and map Inventory as an entity.
Something like (i've skipped the other properties):
public class Product
{
public List<Inventory> Inventory { get; set; }
}
public class Warehouse
{
public List<Inventory> Inventory { get; set; }
}
public class Inventory
{
public Product Product { get; set; }
public Warehouse Warehouse { get; set; }
public bool StockInHand { get; set; }
}
public ProductMap() {
Id(x => x.Id);
Map(x => x.Name);
HasMany(x => x.Inventory)
.Cascade.All()
.Inverse()
.Table("Inventory");
}
public WarehouseMap()
{
Id(x => x.Id);
Map(x => x.Name);
HasMany(x => x.Inventory)
.Cascade.All()
.Inverse()
.Table("Inventory");
}
public InventoryMap()
{
CompositeId()
.KeyReference(x => x.Product, "Product_id")
.KeyReference(x => x.Warehouse, "Warehouse_id")
Map(x => x.StockInHand);
}

Abort due to constraint violation columns GroupId, idx are not unique

I'm using FluentNHibernate and have done a many-to-many mapping but when I try to save my entity I get the following error:
NHibernate.Exceptions.GenericADOException: NHibernate.Exceptions.GenericADOException
: could not insert collection: [Test.Entities.Recipient.Groups#b6815d34-f436-4142-9b8e-1bfcbf25509e][SQL: SQL not available]
---- System.Data.SQLite.SQLiteException : Abort due to constraint violation
columns GroupId, idx are not unique
Here is my mapping:
public class GroupMap : ClassMap<Group>
{
public GroupMap()
{
Id(x => x.Id).GeneratedBy.Guid();
Map(x => x.Name);
Map(x => x.SenderName);
Map(x => x.Created);
HasManyToMany(x => x.Recipients)
.AsList()
.WithTableName("groups_recipients")
.WithParentKeyColumn("GroupId")
.WithChildKeyColumn("RecipientId")
.LazyLoad()
.Cascade.AllDeleteOrphan();
}
}
public class RecipientMap : ClassMap<Recipient>
{
public RecipientMap()
{
Id(x => x.Id).GeneratedBy.Guid();
Map(x => x.Firstname);
Map(x => x.Lastname);
Map(x => x.Phone);
Map(x => x.Email);
HasManyToMany(x => x.Groups)
.AsList()
.WithTableName("groups_recipients")
.WithParentKeyColumn("RecipientId")
.WithChildKeyColumn("GroupId")
.LazyLoad().Cascade.None();
}
}
The problem seems to have something to do with the relationship tables id but I can't figure out how to solve it.
Cheers,
nandarya
Using AsList() was not a good idea. Should be AsBag(). And everything seems to work.

Fluent NHibernate Mapping Error (Id column)

I'm getting a mapping error in Fluent NHibernate. Why is it still looking for _id when I have specified the column explicitly?
Invalid column name 'Account_id'.
[GenericADOException: could not initialize a collection: [ProtoStack.Business.Entities.Account.LedgerEntries#1][SQL: SELECT ***ledgerentr0_.Account_id*** as Account5_1_, ledgerentr0_.Id as Id1_, ledgerentr0_.Id as Id43_0_, ledgerentr0_.LedgerEntryDate as LedgerEn2_43_0_, ledgerentr0_.Amount as Amount43_0_, ledgerentr0_.AccountId as AccountId43_0_ FROM dbo.LedgerEntry ledgerentr0_ WHERE ledgerentr0_.Account_id=?]]
I have explicitly specified that the column is "AccountId".
public class AccountMap : ClassMap<Account>
{
public AccountMap()
{
Table("dbo.Account");
Id(x => x.Id)
.Column("Id");
Map(x => x.Code);
Map(x => x.Name);
Map(x => x.Description);
Map(x => x.Category);
References(x => x.Group)
.Column("AccountGroupId");
HasMany(x => x.LedgerEntries)
.Inverse()
.Cascade.All();
}
}
public class LedgerEntryMap : ClassMap<LedgerEntry>
{
public LedgerEntryMap()
{
Table("dbo.LedgerEntry");
Id(x => x.Id)
.Column("Id");
References(x => x.Account)
.Column("AccountId");
Map(x => x.LedgerEntryDate);
Map(x => x.Amount);
}
}
Am I missing something?
My bad. I was missing KeyColumn.
public class AccountMap : ClassMap<Account>
{
public AccountMap()
{
Table("dbo.Account");
Id(x => x.Id)
.Column("Id");
Map(x => x.Code);
Map(x => x.Name);
Map(x => x.Description);
Map(x => x.Category);
References(x => x.Group)
.Column("AccountGroupId");
HasMany(x => x.LedgerEntries)
.KeyColumn("AccountId")
.Inverse()
.Cascade.All();
}
}
Works now.