Fluent NHibernate mapping one-to-many - fluent-nhibernate

Hello i got problem with my mappings using fluent nhibernate:
public ProductMap()
{
Id(x => x.ProductID);
Map(x => x.ProductName);
Map(x => x.QuantityPerUnit);
Map(x => x.ReorderLevel);
Map(x => x.SupplierID);
Map(x => x.UnitPrice);
Map(x => x.UnitsInStock);
Map(x => x.UnitsOnOrder);
Map(x => x.CategoryID);
Map(x => x.Discontinued);
References(x => x.Category).Column("CategoryID");
References(x => x.Supplier).Column("SupplierID");
Table("dbo.Products");
}
public SupplierMap()
{
Id(x => x.SupplierID);
Map(x => x.Address);
Map(x => x.City);
Map(x => x.CompanyName);
Map(x => x.ContactName);
Map(x => x.ContactTitle);
Map(x => x.Country);
Map(x => x.Fax);
Map(x => x.HomePage);
Map(x => x.Phone);
Map(x => x.PostalCode);
Map(x => x.Region);
HasMany(x => x.Products)
.KeyColumn("SupplierID")
.Inverse()
.Cascade.All();
Table("dbo.Suppliers");
}
public CategoryMap()
{
Id(x => x.CategoryID);
Map(x => x.CategoryName);
Map(x => x.Description);
Map(x => x.Picture);
HasMany(x => x.Products)
.KeyColumn("CategoryID")
.Inverse()
.Cascade.All();
Table("dbo.Categories");
}
when i try to do:
var sessionFactory = SessionFactory.CreateSessionFactory();
using (var session = sessionFactory.OpenSession())
{
Product fresh = new Product()
{
ProductName = "AddFromNhibernate",
SupplierID = 3,
CategoryID = 5,
QuantityPerUnit = "1kg pcg",
UnitPrice = (decimal) 35,
UnitsInStock = (short?) 15,
UnitsOnOrder = 0,
ReorderLevel = null,
Discontinued = true
};
using (session.BeginTransaction())
{
session.Save(fresh);
session.Transaction.Commit();
}
}
I got System.IndexOutOfRangeException.
Whats wrong with my mappings?The work ok when i try to get some data, but adding fails. I trierd to specyfie Propertyreference for Reference in ProductMap but it didn't help.

I noticed you mapped some columns twice.
Take ProductMap as an example:
public ProductMap()
{
(...)
Map(x => x.SupplierID);
(...)
Map(x => x.CategoryID);
References(x => x.Category).Column("CategoryID");
References(x => x.Supplier).Column("SupplierID");
(...)
}
In this case, if you want to preserve the original ID and the reference (since they map to the same column in the database table), you should bypass the Insert/Update in one of them.
What I mean is:
public ProductMap()
{
(...)
Map(x => x.SupplierID).Not.Insert().Not.Update();
(...)
Map(x => x.CategoryID).Not.Insert().Not.Update();
References(x => x.Category).Column("CategoryID");
References(x => x.Supplier).Column("SupplierID");
(...)
}
If you dot not do so, you might get the Exception you described when NHibernate starts to set the insert/update parameters.

Related

Fluent nHibernate mapping with multiple columns

I have following database and I want to create mapping in Fluent nhibernate so that I can traverse object collection like
survey.question.feedback to get all responses to questions .. how can I do that?
I have following mapping so far
public class SurveyMapping : ClassMap<Survey>
{
public SurveyMapping()
{
Id(x => x.Id, "SurveyId");
Map(x => x.Name);
Map(x => x.Type);
Map(x => x.CreationDate);
Map(x => x.ModificationDate);
HasManyToMany<SurveyQuestions>(x => x.Questions).Table("Survey-Questions")
.ParentKeyColumn("SurveyId").ChildKeyColumn("QuestionId").Cascade.All();
HasManyToMany<User>(x => x.Users).Table("User-Surveys").ParentKeyColumn("SurveyId").ChildKeyColumn("UserId").Cascade.None();
}
}
public class SurveyQuestionsMapping : ClassMap<SurveyQuestions>
{
public SurveyQuestionsMapping()
{
Table("Questions");
Id(x => x.Id, "QuestionId");
Map(x => x.QuestionText);
Map(x => x.CommentText);
Map(x => x.Type);
Map(x => x.Scale);
Map(x => x.Rating);
Map(x => x.Threshold);
Map(x => x.CreationDate);
Map(x => x.ModificationDate);
HasMany<UserSurveyFeedback>(x => x.Feedback)
.KeyColumn("QuestionId");
**// This is the confusing part How I can load feedback associated with specific user here**
}
}
You should have many-to-many relations from User to Survey, from User to Feedback, from Question to Survey and from Question to Feedback.
As for querying all feedback from a user, it is simple:
var feedbackFromUser = session.Query<Feedback>().Where(f => f.User.UserID == userID).ToList();

C# NHibernate join problems

I may have possible mapped wrong, or something, NHibernate seems to be confusing to me, but when it works it is smooth. I have Google'd everything to this point and I am still learning NHibernate. I am trying to query an Address that has a accountId, which would link to my AccountUser map, which has a userId that would link to my Usermap. I want to look up all the addresses with the user name of "joe". Anyone know how I would do this with my query? below is my maps, and query:
public AddressMap()
{
Table("Address");
Id(x => x.Id).GeneratedBy.Native();
Map(x => x.FirstName);
Map(x => x.MiddleName);
Map(x => x.LastName);
Map(x => x.CompanyName);
Map(x => x.Street);
Map(x => x.City);
Map(x => x.State);
Map(x => x.AccountID);
Map(x => x.Name);
References(x => x.AccountUser);
}
public class AccountUserMap: ClassMap<AccountUser>
{
public AccountUserMap()
{
Table("AccountUser");
Id(x => x.Id).GeneratedBy.Native();
Map(x => x.UserId);
Map(x => x.AccountID).Not.Nullable();
References(x => x.User);
}
}
public UserMap()
{
Table("User");
Id(x => x.Id).GeneratedBy.Native();
Map(x => x.Name);
}
// non working query:
Address address = null;
User user = null;
AccountUser accountUser = null;
var query = session.QueryOver<Address>(() => address)
.JoinQueryOver(x => x.AccountUser, () => accountUser)
.Where(() => accountUser.AccountID == address.AccountID)
.JoinQueryOver(y => y.User, () => user)
.Where(() => user.Id == accountUser.UserId )
.And(() => user.Name == "joe")
.List()).ToList();
the error message isn't very helpful either...
{"Invalid column name 'AccountUser_id'.\r\nInvalid column name
'User_id'.\r\nInvalid column name 'AccountUser_id'.\r\nInvalid column
name 'User_id'."}
there is nothing named with the underscore, so it must be something with NHibernate
Also, this SQL query below works, and is what I want to do:
SELECT TOP 1000
[AddressID]
,[FirstName]
,[MiddleName]
,[LastName]
FROM Address
inner join AccountUser accountUser
on AccountUser.AccountID = Address.AccountID
inner join User user
on user.UserID = accountUser.UserID
where user.Name= 'joe'
Hopefully thats enough detail
If the property names do not match the database names you have to specify them in the mapping, for example:
Id(x => x.Id, "AddressID").GeneratedBy.Native();
or Fluent NHibernate will use its default naming convention for key columns.

NHibernate Saving an object

I have a profile object that links to a details object (1 to 1). So on my profile object I have the detail object as a property and I am trying to map the details object using a HasOne mapping. When the profile is being saved, it is creating a profile entry in the db and a detail entry; however, the profileId on the details object is Guid.Empty. Its not using the Id its generating on the profile to save the details:
Any ideas?? Thanks in advance
Below are my maps:
public ProfileMap() : base(ESchema.Usr, ETable.Profile)
{
Id(x => x.Id).GeneratedBy.GuidComb();
Map(x => x.MembershipId);
Map(x => x.FirstName);
Map(x => x.LastName);
Map(x => x.Gender).CustomType<EGender>();
Map(x => x.BirthDate);
Map(x => x.IsActive);
HasOne(x => x.Details).PropertyRef(x => x.ProfileId).Cascade.All();
//References(x => x.ProfileImage).Column("ProfileId");
}
public DetailMap() : base(ESchema.Usr, ETable.Detail)
{
Id(x => x.Id).GeneratedBy.GuidComb();
Map(x => x.ProfileId);
Map(x => x.Height);
Map(x => x.Weight);
}
The section on one-to-one in the NHibernate reference (http://nhibernate.info/doc/nh/en/index.html#mapping-declaration-onetoone) seems to suggest (towards the end) that Detail.ProfileId should really be e.g. OwningProfile (typed as Profile) and mapped (in fluent NH) using References().

Inner Join on non-key columns in Nhibernate

The query I am trying to create in Nhibernate:
SELECT _Eligible_Claims.ClaimID, _Eligible_Claims.DateFilled, _Eligible_Claims.NDC, _Eligible_Claims.Cost
From _Eligible_Claims
INNER JOIN _Files_Claims ON _Files_Claims.FileID = _Eligible_Claims.FileID
_Eligible_Claims is a view (thus it has no keys) and _Files_Claims has a PK of "FileID."
Eligible_Claims map:
public EligibleClaimsMap()
{
ReadOnly();
Table("_Eligible_Claims");
Id(x => x.UniqueIdentifier, "Id")
.GeneratedBy.Guid();
Map(x => x.ApplicationID, "ApplicationID")
.Not.Nullable();
Map(x => x.BenOp, "BenOp")
.Not.Nullable();
Map(x => x.BenOpID, "BenOpID")
.Not.Nullable();
Map(x => x.MemberID, "MemberID")
.Nullable();
Map(x => x.ClaimID, "ClaimID")
.Not.Nullable();
Map(x => x.NDC, "NDC")
.Not.Nullable();
Map(x => x.DateFilled, "DateFilled")
.Not.Nullable();
Map(x => x.Cost, "Cost")
.Not.Nullable();
Map(x => x.DrugID, "DrugId")
.Nullable();
Map(x => x.CategoryID, "CategoryId")
.Nullable();
Map(x => x.FileID, "FileID")
.Not.Nullable();
}
_Files_Claims mapping:
public ClamFileMap()
{
Table("_Files_Claims");
Id(x => x.ID, "FileID")
.CustomType<UintToInt>()
.GeneratedBy.Identity();
Map(x => x.Filename, "FileName")
.Not.Nullable();
Map(x => x.Size, "FileSize")
.Not.Nullable();
Map(x => x.DateCreated, "DateCreated")
.Not.Nullable();
Map(x => x.DateEntered, "DateEntered")
.Not.Nullable();
Map(x => x.ClientID, "ClientID")
.Not.Nullable()
.CustomType<UintToInt>();
Map(x => x.MasterTable, "MasterTable")
.Nullable();
Map(x => x.GUID, "GUID")
.Nullable();
Map(x => x.Protected, "Protected")
.Not.Nullable();
Map(x => x.BatchTimeStamp, "BatchTimeStamp")
.Nullable();
Map(x => x.ApplicationID, "ApplicationID")
.Nullable();
Map(x => x.ClaimCount, "Claims")
.Not.Nullable();
Map(x => x.TotalCost, "ClaimCost")
.Not.Nullable();
Map(x => x.PackageID, "PackageID")
.Nullable();
Map(x => x.TempDate, "TempDate")
.Nullable();
Map(x => x.Renamed, "Renamed")
.Not.Nullable();
Map(x => x.ERRPPackage, "ERRPPackage")
.Not.Nullable();
Map(x => x.Removed, "Removed")
.Not.Nullable();
Map(x => x.RemovedBy, "RemovedBy")
.Nullable();
Map(x => x.RemovedDate, "RemovedDate")
.Nullable();
Map(x => x.ImportedBy, "ImportedBy")
.Nullable();
Map(x => x.ImportedDate, "ImportedDate")
.Nullable();
Map(x => x.ControlTotal, "ControlTotal")
.Nullable();
}
My current approach:
var query = session.CreateCriteria<EligibleClaims>()
.CreateAlias("ClaimFile", "claimFile", NHibernate.SqlCommand.JoinType.InnerJoin);
I do not expect that to work because will it not attempt to join the PK of EligibleClaims on the FK of ClaimFile by default? I noticed the "CreateAlias" method has an overload for a 4th parameter of "ICriterion" called "withClause." Any idea how to implement that? Or should I be approaching this from another angle?
if LINQ is an option
var query = from file in session.Query<ClaimFile>()
from claim in session.Query<EligibleClaims>()
where file.FileId == claim.FileId
select new { ... };
Also an option is simply mapping a reference to the _Files_Claims table into the EligibleClaims map. It doesn't HAVE to be a FK but it seems to work anyway:
References(x => x.ClaimFile)
.Column("FileID")
.Not.LazyLoad()
.Cascade.None();
Then use:
var query = session.CreateCriteria<EligibleClaims>()
.CreateAlias("ClaimFile", "claimFile", NHibernate.SqlCommand.JoinType.InnerJoin);
Seems to work.

CompositeId + HasMany doubles the field in the DB

I have such mapping for ProductVariant table:
Id(x => x.Id).Nullable();
Map(x => x.IsEnabled);
Map(x => x.ProductVariantName).Length(45);
Map(x => x.Description);
HasMany(x => x.TestCaseOrdered);
Map(x => x.CreatedDate);
And TestCaseOrder class like this one:
CompositeId().KeyReference(x => x.TestCaseData).KeyReference(x => x.ProductVariant);
Map(x => x.TestCaseOrder);
Map(x => x.TestCaseSetName).Length(45);
But NHibernate generates table TestCaseOrder with two ProductVariant columns:
1) ProductVariant with Primary Key and Not Null.
2) ProductVariantId like a foreign key to the ProductVariant table.
They always have the same data
But I need only one field. How can I achieve that?
seems like a conventionmismatch. Specifying HasMany(x => x.TestCaseOrdered).KeyColumn("ProductVariantId"); and
.KeyReference(x => x.ProductVariant, "ProductVariantId"); should solve it