NHibernate (Fluent) Lazy Loading Not Working - nhibernate

I am attempting to use NHibernate to generate a model for a very odd database. The tables themselves have primary keys for show only, all the actual relationships are on unique columns. For example, a product table with a product id primary key and a unique product name column. Another table, demand, has a product name column and that defines the relationship. I know this situation isn't ideal but it's out of my control.
At any rate, I was able to use Fluent NHibrenate to map product to demand, but I cannot seem to get the entity to lazy-load.
public class Demand
{
public virtual DemandId { get; set; }
public virtual Product { get; set; }
}
public class DemandMap : ClassMap<Demand>
{
public DemandMap()
{
this.Table("Demand");
this.LazyLoad();
this.Id(x => x.DemandId);
this.References(x => x.Product).PropertyRef(x => x.ProductName).LazyLoad();
}
}
Does anyone have any insight into why lazy loading is not working? I know it is not because I can see the product being fetched along with the demand in the SQL profiler.

My idea (Maybe you can try use "HasMany" there is example but you can read something about this):
First class
public class Demand
{
public virtual int DemandId { get; set; }
public virtual int Product { get; set; }
public virtual IEnumerable<NewClass> Name {get; set;}
}
this.HasMany(x=> x.Product).Column("Product_id").not.nullable;
Second class
public class NewClass
{
public virtual Demand Product_id {get; set;}
}
this.References(x => x.Product).Column("product_id).not.nullable

Related

Fluent Nhibernate Cascade.None() results in HasOne foreign key relationship not being persisted

I'm having issues with Nhibernate persisting a HasOne Relationship for one of my entities with Cascade.None() in effect. My domain model involves 4 classes listed below.
public class Project
{
public virtual int Id {get;set;}
public virtual IList<ProjectRole> Team { get; protected set; }
}
public class ProjectRole
{
public virtual int Id { get; set; }
public virtual User User { get; set; }
public virtual Role Role { get; set; }
}
public class Role
{
public virtual int Id { get; set; }
public virtual string Value { get; set; }
}
public class User
{
public virtual int Id { get; protected set; }
public virtual string LoginName { get; set; }
}
So basically we have projects, which have a list of ProjectRoles available from the Team property. Each ProjectRole links a User to the specific Role they play on that project.
I'm trying to setup the following cascade relationships for these entities.
project.HasMany<ProjectRoles>(p=> p.Team).Cascade.All()
projectRole.HasOne<Role>(r => r.Role).Cascade.None()
projectRole.HasOne<User>(r => r.User).Cascade.SaveUpdate()
I've used fluent nhibernate overrides to setup the cascades as above, but I'm finding that the line
projectRole.HasOne<Role>(r => r.Role).Cascade.None()
is resulting in the ProjectRole.Role property not being saved to the database. I've diagnosed this be looking at the SQL Generated by Nhibernate and I can see that the "Role_id" column in the ProjectRoles table is never set on update or insert.
I've also tried using
projectRole.HasOne<Role>(r => r.Role).Cascade.SaveUpdate()
but that fails as well. Unfortunately leaving it Cascade.All() is not an option as that results in the system deleting the Role objects when I try to delete a project role.
Any idea how to setup Cascade.None() for the ProjectRole-> Role relationship with out breaking persistence.
HasOne is for a one-to-one relationship which are rare. You want to use References to declare the one side of a one-to-many relationship. Making some assumptions about your domain model, the mapping should look like:
project.HasMany<ProjectRoles>(p=> p.Team).Inverse().Cascade.AllDeleteOrphan()
projectRole.References<Role>(r => r.Role);
projectRole.References<User>(r => r.User);
See also this question about the difference between HasOne and References.

Fluent Nhibernate Many to Many association to multiple classes

Fluent Nhibernate Many to Many association to multiple classes
We use Nhibernate and up to now we have been able use the auto mapping. But I think this is about to change.
We have a Code class that has a many to many relation with several other classes.
I’m thinking something along these lines:
public class Code
{
public virtual Guid Id { get; set; }
public virtual ICollection<CodeUsage> Usage { get; set; }
}
class CodeUsage
{
public virtual Guid Id { get; set; }
public virtual Code Code { get; set; }
// Class, [Property,] Id for "ANY" mapping to A & B
}
class A
{
public virtual Guid Id { get; set; }
public virtual ICollection<CodeUsage> Codes { get; set; }
}
class B
{
public virtual Guid Id { get; set; }
public virtual ICollection<CodeUsage> Codes { get; set; }
}
Many to Many will lead to the creation of a linking table, in the linking table their needs come a mapping to the classes using codes. In the documentation it is referred to as a “Any” mapping.
But I have no idea how get fluent to create one.
Thoughts anyone? or even better: a solution <);o)}{
You can't map <many-to-any> in Fluent NHibernate - it's not supported.
I think it may be a good reason to move to mapping-by-code, that supports it well.

Entity Framework Code First Class with parent and children of same type as it's own class

I have a class of Content which should be able to have a parentId for inheritance but also I want it to have a list of child content which is nothing to do with this inheritance tree.
I basically wanted a link table as ChildContentRelationship with Id's for parentContent and childContent in it and the Content class would have a list of ChildContentRelationship.
This has caused a lot of errors.
Here's waht I sort of want to do
public class Content
{
public int Id { get; set; }
public int? ParentContentId { get; set; }
public virtual Content ParentContent { get; set; }
public string Name { get; set; }
public int ContentTypeId { get; set; }
public virtual ContentType ContentType { get; set; }
public virtual ICollection<Property> Properties { get; set; }
public virtual ICollection<ChildContentRelationship> ChildContent { get; set; }
}
How would I set this up in EF?
I am not sure if I understand your model correctly. Let's discuss the options.
For a moment I omit this additional entity ChildContentRelationship and I assume the ChildContent collection is of type ICollection<Content>.
Option 1:
I assume that ParentContent is the inverse property of ChildContent. It would mean that if you have a Content with Id = x and this Content has a ChildContent with Id = y then the ChildContents ParentContentId must always be x. This would only be a single association and ParentContent and ChildContent are the endpoints of this same association.
The mapping for this relationship can be created either with data annotations ...
[InverseProperty("ParentContent")]
public virtual ICollection<Content> ChildContent { get; set; }
... or with Fluent API:
modelBuilder.Entity<Content>()
.HasOptional(c => c.ParentContent)
.WithMany(c => c.ChildContent)
.HasForeignKey(c => c.ParentContentId);
I think this is not what you want ("...has nothing to do with..."). Consider renaming your navigation properties though. If someone reads Parent... and Child... he will very likely assume they build a pair of navigation properties for the same relationship.
Option 2:
ParentContent is not the inverse property of ChildContent which would mean that you actually have two independent relationships and the second endpoint of both relationships is not exposed in your model class.
The mapping for ParentContent would look like this:
modelBuilder.Entity<Content>()
.HasOptional(c => c.ParentContent)
.WithMany()
.HasForeignKey(c => c.ParentContentId);
WithMany() without parameters indicates that the second endpoint is not a property in your model class, especially it is not ChildContent.
Now, the question remains: What kind of relationship does ChildContent belong to? Is it a one-to-many or is it a many-to-many relationship?
Option 2a
If a Content refers to other ChildContents and there can't be a second Content which would refer to the same ChildContents (the children of a Content are unique, so to speak) then you have a one-to-many relationship. (This is similar to a relationship between an order and order items: An order item can only belong to one specific order.)
The mapping for ChildContent would look like this:
modelBuilder.Entity<Content>()
.HasMany(c => c.ChildContent)
.WithOptional(); // or WithRequired()
You will have an additional foreign key column in the Content table in your database which belongs to this association but doesn't have a corresponding FK property in the entity class.
Option 2b
If many Contents can refer to the same ChildContents then you have a many-to-many relationship. (This is similar to a relationship between a user and roles: There can be many users within the same role and a user can have many roles.)
The mapping for ChildContent would look like this:
modelBuilder.Entity<Content>()
.HasMany(c => c.ChildContent)
.WithMany()
.Map(x =>
{
x.MapLeftKey("ParentId");
x.MapRightKey("ChildId");
x.ToTable("ChildContentRelationships");
});
This mapping will create a join table ChildContentRelationships in the database but you don't need a corresponding entity for this table.
Option 2c
Only in the case that the many-to-many relationship has more properties in addition to the two keys (ParentId and ChildId) (for example something like CreationDate or RelationshipType or...) you would have to introduce a new entity ChildContentRelationship into your model:
public class ChildContentRelationship
{
[Key, Column(Order = 0)]
public int ParentId { get; set; }
[Key, Column(Order = 1)]
public int ChildId { get; set; }
public Content Parent { get; set; }
public Content Child { get; set; }
public DateTime CreationDate { get; set; }
public string RelationshipType { get; set; }
}
Now your Content class would have a collection of ChildContentRelationships:
public virtual ICollection<ChildContentRelationship> ChildContent
{ get; set; }
And you have two one-to-many relationships:
modelBuilder.Entity<ChildContentRelationship>()
.HasRequired(ccr => ccr.Parent)
.WithMany(c => c.ChildContent)
.HasForeignKey(ccr => ccr.ParentId);
modelBuilder.Entity<ChildContentRelationship>()
.HasRequired(ccr => ccr.Child)
.WithMany()
.HasForeignKey(ccr => ccr.ChildId);
I believe that you want either option 2a or 2b, but I am not sure.

How to create mapping relationship using Fluent NHibernate

How can I map one-to-many relationship with
User to Address,
Customer to Address,
Agency to Address and
store in a single Address Table using Fluent NHibernate
public class User
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual IList<Address> Address { get; set; }
}
public class Customer
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual IList<Address> Address { get; set; }
}
public class Agency
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual IList<Address> Address { get; set; }
}
public class Address
{
public virtual int Id { get; set; }
public virtual string Address1 { get; set; }
public virtual string Address2 { get; set; }
public virtual string City { get; set; }
public virtual string State { get; set; }
}
I think you'll need to store your relations independently to connect addresses and users/customers/agencies if you want to be able to use the same address for all types. This involves introducing a new table that only stores ID pairs, and making that the storage location for your relationship.
You can map collections as many-to-many and use the table method to name your link table. Your mapping would look something like:
public UserMap : ClassMap<User> {
Id (u => u.Id);
Map (u => u.Name);
HasManyToMany (u => u.Addresses).Table ("UsersXAddresses");
}
You'll need a similar link table for customers and agencies.
In the constructor for your mapping class, map the link using the HasMany method. HasMany will create a one-to-many relationship. HasManyToMany will create a many-to-many relationship.
For example: HasMany(x => x.Address).LazyLoad();
This will create a one-to-many relationship between the User class and the Address class.
For the many-to-many, you will also need to specify the table name and if you so desire, the left and right side table mappings.
For example: HasManyToMany(x => x.Address).Table("AddressToUser").ParentKeyColumn("AddressId").ChildKeyColumn("UserId").LazyLoad();
If you decide that you want to set up a distinction between a UserAddress and an AgencyAddress (where these are sub-classes of Address) - you can use the DiscriminateSubClassesOnColumn method in the AddressMap class so the FNH knows to create an extra column in order to determine which type of object to create.
For example: DiscriminateSubClassesOnColumn("Type").AlwaysSelectWithValue();
You should be able to use FNH Automapping to map these classes "as is".
It will handle all the relationships in your object model.
I believe it will put all the addresses in a single Address table as you desire, but can't say for sure.

Fluent NHibernate Mapping not on PK Field

I have the following tables and cannot edit their structure...
Person
------
Id PK
Code
Name
Order
-----
Id PK
Person_Code
OrderDetails
Now in my Person class I want to have a list of Orders for that person, but I'm not entirely sure how to go about setting up the mapping in fluent nhibernate to match on the Code column rather than the ID. There is no foreign key constraint and I am unable to change the database to use the keys. Something like this is what I require, but can;t seem to figure out the mapping.
public class Person
{
public virtual int Id { get; set; }
public virtual string Code { get; set; }
public virtual IList<Order> Orders { get; private set; }
}
public class Order
{
public virtual int Id { get; set; }
public virtual string OrderDetails { get; set; }
public virtual Person Owner { get; set; }
}
You define your column with the KeyColumn method. It should work regardless of existence of a foreign key constraint.
class PersonMap : ClassMap<Person>
{
public PersonMap()
{
HasMany(p => p.Order)
.KeyColumn("Person_Code")
.PropertyRef("Code");
}
}
PropertyRef method is available from rev 614 so you may need to update the fluent nhibernate version.