Is there a way of writing an NHibernate mapping so that you can have an entity that is composed of fields from different DB tables?
For Example is I have a Person and Address table, I want address fields to appear in my person object.
I want an entity like this:
public class person
{
public virtual Guid Key{get; set;}
public virtual string Name {get; set;}
public virtual string Age {get; set;}
public virtual string Address1 {get; set;} //from address table
public virtual string Address2 {get; set;} //from address table
}
If you are using Fluent NHibernate you can use WithTable, as in this example:
public class PersonMap : ClassMap<Person>
{
public PersonMap()
{
Id(x => x.Key, "[Key]"); // Explicitly specify escaped column name to
// avoid problems with reserved words
Map(x => x.Name);
Map(x => x.Age);
WithTable("Address", m =>
{
m.Map(x => x.Address1);
m.Map(x => x.Address2);
});
}
}
I think here's what you need. Not sure about support on Fluent NHibernate part, as well as I'm not sure about the validity of this idea.
You could also consider using a many-to-many table between Person and Address. In that case, it might make sense to have a property "Addresses" that can just hold a list of however many addresses you want.
You can do a mapping (or whatever collection mapping works best) with a mapping to accomplish this.
Related
I have a table called "Customers" and in this table there are store and office address. In the code there is a Customer class with two properties that are of type Address (one for StoreAddress and OfficeAddress).
public class Customer
{
public virtual int Id { get; set;}
public virtual string Name {get;set;}
public virtual string Email {get; set;}
public virtual Address StoreAddress {get; set;}
public virtual Address OfficeAddress {get; set;}
}
public class Address
{
public string Address1 {get; set;}
public string Address2 {get; set;}
public string State {get; set;}
public string City {get; set;}
public string Zip {get; set;}
}
I can map items that are not of an entity type Address but not sure how to map to another entity property within the customer entity?..
Table("Customers");
Schema("dbo);
Id(x => x.ID).Column("CustomerId");
Map(x => x.Name);
Map(x => x.Email);
How would I be able to map to my StoreAddress and OfficeAddress from the table Customers table?
You can use component mapping:
Component(x => StoreAddress).ColumnPrefix("StoreAddress");
Component(x => OfficeAddress).ColumnPrefix("OfficeAddress");
Then create a component map for Address type:
public class AddressMap : ComponentMap<Address>
{
public AddressMap()
{
//map properterties
}
}
In case, I understand your missing point, we can use:
References / many-to-one
References is for creating many-to-one relationships between two entities, and is applied on the "many side." You're referencing a single other entity, so you use the References method. #HasMany / one-to-many is the "other side" of the References relationship, and gets applied on the "one side."
Table("Customers");
Schema("dbo);
Id(x => x.ID).Column("CustomerId");
Map(x => x.Name);
Map(x => x.Email);
// this is the fluent way for many-to-one
References(x => x.StoreAddress);
References(x => x.OfficeAddress);
The complete overview of the References() syntax could be found here: Mapping-by-Code - ManyToOne (by Adam Bar) - which is about mapping-by-code, but provides comparison with fluent syntax (the second half of the post)
I am trying to use fluent nHibernate to map a class that only exists as a container for other classes, and doesn't have an Id of its own. But I want the Id of the class to be a different class. That really doesn't make sense, it might be easier to explain with an example data structure.
abstract QueryBuilder
{
public IEnumerable<string> Category1Keys {get; set;}
public IEnumerable<int> Category2Ids {get; set;}
public IEnumerable<int> Category3Ids {get; set;}
}
Set
{
public int Id {get; set;}
public string Name {get; set;}
public SetQueryBuilder QueryBuilder{get; set;}
}
SetQueryBuilder : QueryBuilder
{
}
News
{
public int Id {get; set;}
public string Name {get; set;}
public NewsQueryBuilder QueryBuilder{get; set;}
}
NewsQueryBuilder : QueryBuilder
{
}
Now the QueryBuilder is the name is a concept that we use to map various (unrelated) items to the same categories. So things that might use QueryBuidler are News, Pages, Permissions.
Becuase all the various items that use QueryBuilder map that relationship in the same way, and ocasionally we actually use the paramters from one type of QueryBuilder as a the select criteriea for another type of QueryBuilder (ie if news has QB of A, get all the Sets that match the same criteria), I want to have a abstract QueryBuilder class, and then extend it for all the things that have mappings to all the categories.
Here is an example of the Set DB for query builder. There isn't an actual item in the DB for QueryBuilder - its composed of all the info from the category class join tables.
f_set
{
set_id (PK, int)
name (varchar)
}
f_set_cat1
{
set_id (PK, FK, int)
cat1_key (PK, FK, char(3))
}
f_set_cat2
{
set_id (PK, FK, int)
cat2_id (PK, FK, int)
}
f_set_cat3
{
set_id (PK, FK, int)
cat3_id (PK, FK, int)
}
My problem is how to map each instance of the QueryBuilder class in nHibernate, as it doesnt' have a real key or table entry, I would like to say that the Id is a reference to the Set that all the category mappings use.
Here are my fluent mappings so far:
SetMapping : ClassMap<Set>
{
public SetMapping()
{
Schema("cam");
Table("f_set");
Id(x => x.Id, "f_set_id").GeneratedBy.Identity();
Map(x => x.Name, "name").Not.Nullable();
HasOne<SetQueryBuilder>(x => x.QueryBuilder);
}
}
SetQueryBuilderMapping : ClassMap<SetQueryBuilder>
{
public SetQueryBuilderMapping()
{
References(x => x.Set, "set_id");
HasMany(x => x.Category1Keys).Table("f_set_cat1").Element("cat1_key").KeyColumn("set_id");
HasMany(x => x.Category2Ids).Table("f_set_cat2").Element("cat2_id").KeyColumn("set_id");
HasMany(x => x.Category2Ids).Table("f_set_cat3").Element("cat3_id").KeyColumn("set_id");
}
}
Any help with the final step of the mapping would be hugely appreciated
Thanks
Saan
FURTHER INVESTIGATION
Ok I have done a bit mroe investigating on this and have foudn that combining the two classes works fine if I do this:
CLASS:
Set
{
public int Id {get; set;}
public string Name {get; set;}
//public SetQueryBuilder QueryBuilder{get; set;}
public IEnumerable<string> Category1Keys {get; set;}
public IEnumerable<int> Category2Ids {get; set;}
public IEnumerable<int> Category3Ids {get; set;}
}
MAPPING
SetMapping : ClassMap<Set>
{
public SetMapping()
{
Schema("cam");
Table("f_set");
Id(x => x.Id, "f_set_id").GeneratedBy.Identity();
Map(x => x.Name, "name").Not.Nullable();
//HasOne<SetQueryBuilder>(x => x.QueryBuilder);
HasMany(x => x.Category1Keys).Table("f_set_cat1").Element("cat1_key").KeyColumn("set_id");
HasMany(x => x.Category2Ids).Table("f_set_cat2").Element("cat2_id").KeyColumn("set_id");
HasMany(x => x.Category2Ids).Table("f_set_cat3").Element("cat3_id").KeyColumn("set_id");
}
}
When doing nHibernate mappings this makes perfect sense, but I would really like to have all the category mappings in the separate SetQueryBuilder class.
Thanks again for any help
Saan
You are looking for subclassing strategy. Take a look at this http://nhibernate.info/doc/nh/en/index.html#inheritance
You probably want to follow a table per class with table per subclass strategy imo.
public class Node
{
public virtual int Id {get; set;}
public virtual string Name {get; set;}
public virtual IList<Node> Ancestors {get; set;}
public virtual IList<Node> Descendants {get; set;}
}
how to setup the mapping convention for this case?
thank you
Are you sure you want a convention? I am going to guess you just want a fluent mapping. Here's an example from the last time I helped someone with this:
public class CustomerMap : ClassMap<Customer>
{
public CustomerMap()
{
Id(x => x.CustomerId);
Map(x => x.Birthday);
Map(x => x.FirstName);
HasManyToMany(x => x.Parents)
.ParentKeyColumn("ChildID")
.ChildKeyColumn("ParentID")
.Inverse();
HasManyToMany(x => x.Children)
.ParentKeyColumn("ParentID")
.ChildKeyColumn("ChildID");
}
}
See here for the original thread. That thread has a link to an example project I made for demonstrating self referencing many-to-many relationships, which is here.
I have an interesting issue, which I can't seem to find a satisfying answer for. It concerns join tables.
Basically (I'm sure this has been out here in some form or another, but I cant find it) I have 3 tables. A Person table, Address table, PersonAddress..
Person
PersonID
Name
Age
etc..
Address
AddressID
AddressLine1
AddressLine2
City
State
Zip
PersonAddress
AddressID
PersonID
AddressType
The reason why AddressType is on the join table is simply because these addresses can be shared amongst people throughout the company, as a Shipping type, Physical Location, or Billing.
Is there even possibly away to join these as a collection or something
I would like to manage something like this
Address Class
AddressLine1
AddressLine2
City
State
Zip
AddressType
Person Class
Name
Age
IListAddresses
This person would hold a collection of addresses for himself.
If anyone has a way that I could accomplish this in Fluent or just straight XML mapping, that would be terrific. I just feel this should be something easy, but I am missing it. And not having the correct termonology (bridge table, join table, collection table, join-parts table) I cant seem to google to save my life.
Thanks in advance to any help!
I think this can be achieved pretty easily if I understand correctly. :) You have a Person object and you want it to contain some properties and a collection of person's addresses that can also be shared amongst other users, right? Well, to set this up using Fluent NHibernate I would do something like this:
// Person Entity
public class Person
{
public int Id { get; private set; }
public string Name { get; set; }
public IList<PersonAddress> Addresses { get; set; }
}
// Fluent Mapping
public class PersonMap : ClassMap<Person>
{
public PersonMap() {
Id(x => x.Id);
Map(x => x.Name);
HasMany(x => x.Addresses).Cascade.All();
}
}
// Address Entity
public class Address
{
public int Id { get; private set; }
public string Address1 { get; set; }
public string City { get; set; }
public IList<PersonAddress> People { get; set; }
}
// Fluent Mapping
public class AddressMap : ClassMap<Address>
{
public AddressMap() {
Id(x => x.Id);
Map(x => x.Address1);
Map(x => x.City);
HasMany(x => x.People).Cascade.All();
}
}
// PersonAddress Entity
public class PersonAddress
{
public int Id { get; private set; }
public Person Person { get; set; }
public Address Address { get; set; }
public AddressType Type { get; set; }
}
// Fluent Mapping
public class PersonAddressMap : ClassMap<PersonAddress>
{
public PersonAddressMap() {
Id(x => x.Id);
References(x => x.Person);
References(x => x.Address);
Map(x => x.Type).CustomTypeIs(typeof(AddressType));
}
}
Basically, this allows a Person to have a collection of Addresses and those Addresses can be shared amongst the company (multiple persons). You almost have a many-to-many setup but because you storing state info in the PersonAddress it became two one-to-many relationships in the Person and Address Entity.
Sorry if I gave you more than you wanted! Just felt like typing! :p
Let me know if this helps or if you have any questions or if I'm totally off base.
I would move AddressType off PersonAddress table and put it on the Address Table. Then you should be able to map a regular Many-to-Many mapping.
public class PersonMap : ClassMap<Person>
{
public PersonMap()
{
Id(x => x.PersonId);
Map(x => x.Name);
HasManyToMany(x => x.Addresses)
.Cascade.All()
.WithTableName("PersonAddress");
}
}
Can you setup a database View that joins the Person and PersonAddress tables. An nHibernate Address object can then be created that contains an AddressType even though underneith you have the table structure you want.
Basic question: How to I create a bidirectional one-to-many map in Fluent NHibernate?
Details:
I have a parent object with many children. In my case, it is meaningless for the child to not have a parent, so in the database, I would like the foreign key to the parent to have NOT NULL constraint. I am auto-generating my database from the Fluent NHibernate mapping.
I have a parent with many child objects like so:
public class Summary
{
public int id {get; protected set;}
public IList<Detail> Details {get; protected set;}
}
public class Detail
{
public int id {get; protected set;}
public string ItemName {get; set;}
/* public Summary Owner {get; protected set;} */ //I think this might be needed for bidirectional mapping?
}
Here is the mapping I started with:
public class SummaryMap : ClassMap<Summary>
{
public SummaryMap()
{
Id(x => x.ID);
HasMany<Detail>(x => x.Details);
}
}
public class DetailMap : ClassMap<Detail>
{
public DetailMap()
{
Id(x => x.ID);
Map(x => x.ItemName).CanNotBeNull();
}
}
In the Detail table, the Summary_id should be Not Null, because in my
case it is meaningless to have a Detail object not attached to the
summary object. However, just using the HasMany() map leaves the Summary_id foreign key nullable.
I found in the NHibernate docs (http://www.hibernate.org/hib_docs/nhibernate/html/collections.html) that "If the parent is required, use a bidirectional one-to-many association".
So how do I create the bidirectional one-to-many map in Fluent NHibernate?
To get a bidirectional association with a not-null foreign key column in the Details table you can add the suggested Owner property, a References(...).CanNotBeNull() mapping in the DetailsMap class, and make the Summary end inverse.
To avoid having two different foreign key columns for the two association directions, you can either specify the column names manually or name the properties in a way that gives the same column name for both directions. In this case you I suggest renaming the Details.Owner property to Details.Summary.
I made the Summary id generated by increment to avoid problems when inserting into the table since Summary currenty has no columns besides id.
Domain:
public class Detail
{
public int id { get; protected set; }
public string ItemName { get; set; }
// Renamed to use same column name as specified in the mapping of Summary.Details
public Summary Summary {get; set;}
}
public class Summary
{
public Summary()
{
Details = new List<Detail>();
}
public int id { get; protected set; }
public IList<Detail> Details { get; protected set; }
}
Mapping:
public class DetailMap : ClassMap<Detail>
{
public DetailMap()
{
Id(x => x.id)
.GeneratedBy.Native();
Map(x => x.ItemName)
.CanNotBeNull();
References<Summary>(x => x.Summary)
// If you don't want to rename the property in Summary,
// you can do this instead:
// .TheColumnNameIs("Summary_id")
.CanNotBeNull();
}
}
public class SummaryMap : ClassMap<Summary>
{
public SummaryMap()
{
Id(x => x.id)
.GeneratedBy.Increment();
HasMany<Detail>(x => x.Details)
.IsInverse()
.AsBag(); // Use bag instead of list to avoid index updating issues
}
}