CompositeId + HasMany doubles the field in the DB - nhibernate

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

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.

Fluent NHibernate mapping one-to-many

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.

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().

Auto save in fluent nhibernate does not work

I have a problem.
When I try to insert an object with the type book to the DB,
It should add the author also to the authors table if it doesnt exist.
Instead I get an error 'unsaved object' and the object has not been saved.
whats the problem?
the code:
Book:
Id(x => x.ID);
Map(x => x.Title);
References(x => x.Author)
.Not.LazyLoad()
.Column("Author_id");
Author:
Id(x => x.ID);
Map(x => x.FullName);
References(x => x.Author)
.Not.LazyLoad()
.Cascade.All() // unsaved Authors should also be saved
.Column("Author_id");
don't forget you have to use session.Get/session.Load to get existing Authors