How can I use a composite-id with a class as the id field in fluent nhibernate? - fluent-nhibernate

I've got a mapping file like this:
<class name="Resource" table="resource" discriminator-value="null">
<composite-id name="Key" class="Models.Bases.ClientKey, Models">
<key-property name="Id" column="ID" type="int"/>
<key-property name="SiteId" column="clientID" type="int"/>
</composite-id>
<property name="Name" type="String">
<column name="`name`" length="500" sql-type="varchar" not-null="false"/>
</property>
</class>
which works just fine and here's the id class:
public class ClientKey
{
public int Id { get; set; }
public int ClientId { get; set; }
}
public class Resource
{
public virtual ClientKey Key { get; set; }
public virtual string Name { get; set; }
}
How can I remap this using FluentNhibernate? This code doesn't work:
WithTable("resource");
UseCompositeId()
.WithKeyProperty(x => x.Key.Id, "ID")
.WithKeyProperty(x => x.Key.ClientId, "clientID");
Map(x => x.Name);
It throws this error:
Could not find a getter for property 'Id' in class 'Models.Resource'
Thanks!!!

I'm afraid you can't fix it without modifying Resource class. I have checked with Fluent NHibernate's source - here's what code that outputs composite-id part looks like:
XmlElement element = classElement.AddElement("composite-id");
foreach( var keyProp in keyProperties )
{
keyProp.Write(element, visitor);
}
What is missing is "name" attribute, which should be set to "Key". Without this attibute, NHibernate fallbacks to default property name = "Id". As your class doesn't have Id property, NHibernate doesn't know what to do and throws an exception.
If you can't modify Resource class, you would have to use hbm mapping for this class or create a patch to fluent nhibernate (it is possible that this is known issue and someone's working on it - refer to fluent nhibernate's issue tracker).

Related

Mapping a column multiple times in Nhibernate

I have for example an entity. With the following properties:
public class Entity
{
public int CustomerId { get; set; }
public Customer { get; set; }
}
How can I map the CustomerId twice. Once for the int property and once for the many-to-one relationship ?
<many-to-one name="Customer" column="[CustomerId]" class="Customer"/>
<property name="CustomerId" column="[CustomerId]" type="Int64" />
Just this, doesn't work. I've already tried, making them readonly but no success.
One of them should be mapped as readonly (inser/udpate false), and referenced as formula
<many-to-one name="Customer" column="[CustomerId]" class="Customer"/>
<property name="CustomerId" formula="[CustomerId]" type="Int64" insert="false" update="false" />
Then it should be working correctly. Both properties then can be used for Select, Where... order by
You don't need to map CustomerId, you can access it through Customer.CustomerId. If you're using lazy loading, CustomerId will be populated in the proxy object so it's always available without triggering an additional select.
If you absolutely have to expose it, expose it as a nullable read only property:
public Customer { get; set; }
public int? CustomerId
{
get { return Customer == null ? (int?)null: Customer.CustomerId }
}

NHibernate mapping

I use HBM mapping.
I have tables :
I) person with columns :
1. ID
2. TYPE
3.CREATE_DATE
4.UPDATE_DATE
II) Attribute with columns:
1.ID
2.TYPE(in this example person may be all type)
3.NAME
4.CREATE_DATE
5.UPDATE_DATE
III) Attribute_VALUE with columns:
1.ID
2.VALUE
4.OBJECT_ID
5.ATTRIBUTE_ID
6.CREATE_DATE
7.UPDATE_DATE
There is relationship one-to-many between person(ID) and Attribute_VALUE(OBJECT_ID).
There is relationship one-to-many between Attribute(ID) and Attribute_VALUE(ATTRIBUTE_ID)
I need build object PERSON that contain all columns of person and dictionary with name attribute.
The dictionary contain key - name of attribute value- collection of values .
Can I build appropriate HBM ??
the short answer no.
the long answer:
consider how should nhibernate match attributes when you Attributes.Add("foo", "value")? it has to search the db for an attribute foo (which is not a simple mapping, its logic) or it would create a new Attribute, everytime you add one.
So given the above schema you either a) have some kind of custom onsave code (which i think is a lot of effort) or b) you change the Person to
class Person
{
public virtual int Id { get; set; }
public virtual ICollection<AttributeValue> Attributes { get; set; }
public virtual IEnumerable<string> GetValues(string attributeName)
{
return Attributes
.Where(attr => attr.Attribute.Name == attributeName)
.Select(attr => attr.Value);
}
public virtual void AddValue(Attribute attribute, string value)
{
Attributes.Add(new AttributeValue
{
Attribute = attribute,
Value = value
});
}
public virtual IEnumerable<string> GetAttributeNames()
{
return Attributes
.Select(attr => attr.Attribute.Name);
}
}
class Attribute
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
// and more Properties like created and updated
}
class AttributeValue
{
public virtual int Id { get; set; }
public virtual Attribute Attribute { get; set; }
public virtual string Value { get; set; }
// and more Properties like created and updated
}
and then use
<class name="Person" table="Persons" xmlns="urn:nhibernate-mapping-2.2">
<id name="Id" column="ID"/>
<bag name="Attributes">
<key column="OBJECT_ID"/>
<one-to-many class="AttributeValue"/>
</bag>
</class>
<class name="Attribute" table="Attributes" xmlns="urn:nhibernate-mapping-2.2">
<id name="Id" column="ID"/>
<property name="Name" column="Name"/>
<!--additional properties-->
</class>
<class name="AttributeValue" table="AttributeValues" xmlns="urn:nhibernate-mapping-2.2">
<id name="Id" column="ID"/>
<many-to-one class="Attribute" column="ATTRIBUTE_ID"/>
<property name="Value" column="Value"/>
<!--additional properties-->
</class>

Nhibernat mapping aspnet_Users table

My User table I want to map to aspnet_Users:
<class name="User" table="`User`">
<id name="ID" column="ID" type="Int32" unsaved-value="0">
<generator class="native" />
</id>
<property name="UserId" column="UserId" type="Guid" not-null="true" />
<property name="FullName" column="FullName" type="String" not-null="true" />
<property name="PhoneNumber" column="PhoneNumber" type="String" not-null="false" />
</class>
My aspnet_Users table:
<class name="aspnet_Users" table="aspnet_Users">
<id name="ID" column="UserId" type="Guid" />
<property name="UserName" column="UserName" type="string" not-null="false" />
</class>
I tried adding one-to-one, one-to-many and many-to-one mappings. The closest I can get is with this error: Object of type 'System.Guid' cannot be converted to type 'System.Int32'.
How do I create a 1 way mapping from User to aspnet_User via the UserId column in User?
I am only wanting to create a reference so I can extract read-only information, affect sorts, etc. I still need to leave UserId column in User set up like it is now. Maybe a virtual reference keying off of UserId? Is this even possible with Nhibernate?
Unfortunately it acts like it only wants to use ID from User to map to aspnet_Users. Changing the table User to have it's primary key be UserId instead of ID is not an option at this point.
Any help would be greatly appreciated. Thanks in advance.
Aspnet_user table has a primary key of type Guid.
Your table User has a primary key of type Int32.
You can look at this as your user table has a reference (one to one) to aspnet_users table.
But if you look at the aspnet_users table as if it is a 'basket of values' to assign to a user (like if you'd have a type of user (admin, moderator, ...), but that would be many-to-one refrence (many users have one of the type) you can map it like that.
So:
class User
{
public virtual int ID { get; set; }
public virtual Guid UserId { get; set; }
public virtual string FullName { get; set; }
public virtual string PhoneNumber { get; set; }
}
class AspnetUser
{
public virtual Guid ID { get; set; }
public virtual string UserName { get; set; }
}
mapping would be (using fluent.NHibernate):
public class User_Map : ClassMap<User>
{
public User_Map()
{
Table("User");
ID(x => x.ID).GeneratedBy.Native();
References(x => x.UserId);
Map(x => x.FullName);
Map(x => x.PhoneNumber);
}
}
public class AspnetUser_Map : ClassMap<AspnetUser>
{
public User_Map()
{
Table("aspnet_Users");
ID(x => x.ID).GeneratedBy.Assigned();
Map(x => x.UserName);
}
}
To get some further guidance on this, have a look at the NHibernateProvider project. They have created a full membership provider implementation that uses NHibernate under the hood.

How to setup Fluent NHibernate Many-To-Many automapping using Set instead of Bag?

http://www.codinginstinct.com/2010/03/nhibernate-tip-use-set-for-many-to-many.html
I want to do the way the author suggested for fluent nhibernate many-to-many but use automapping instead of HBM file.
Here are my two entities
public class User
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual Iesi.Collections.Generic.Set<City> Cities { get; set; }
}
public class City{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual Iesi.Collections.Generic.Set<User> Users { get; set; }
}
Tried with HashSet, IList, and Set. But when I looked at the HBM files generated by calling automapping output method:
var autoMappings = new AutoPersistenceModel().AddEntityAssembly(entityAssembly).Where(x => x.Namespace.EndsWith("Domain"));
autoMappings.WriteMappingsTo((#"C:\TEMP");
It's still bag type
<bag inverse="true" name="Users" table="MNUserCity" mutable="true">
<key>
<column name="CityId" />
</key>
<many-to-many class="MyApp.Entity.Domain.User, MyApp.Entity, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
<column name="UserId" />
</many-to-many>
</bag>
Is there any conventions/override I can use in Fluent NHibernate to alter the collection type for all the ManyToMany in the app domain? I looked at IHasManyToMany convention but no clue.
Anyone can help? Thanks.
BTW, I'm using latest build in http://github.com/jagregory/fluent-nhibernate
Changing the type of Users and Cities from Set to ISet should solve your issue.
As stated by James in this thread, "The automapper is very opinionated and inflexible, and it expects collections to be exposed as IList or ISet."

Complicated NHibernate component mapping

EDIT: I simplified the problem to leave only what really bothers me.
Hello all,
I am trying to make the following mapping.
In my database, I have a table called "ReportRowValue" containg the following columns:
RowNumber
ColumnNumber
StringValue
LongValue
DateValue
Value
In my code I want to get a more usable structure by creating several two classes from this one table. I guess this should be done using components and inheritance but I did not managed to create a working mapping file. What I want in code should look like this:
ReportRow
RowNumber
Values (collection of ReportValue below)
ReportValue (being an abstract class)
ColumnNumber
Value
ReportValueString / ReportValueLong / ReportValueDate (each one inheriting from ReportValue)
Value (each one having a Value property of its one type)
And that's about all!
Does anyone can point me how to create an nhibernate mapping file/files for doing that?
Thanks,
Meigetsu
There is couple of tools that maps and builds class for you one of them is
mygeneration
is the software http://sourceforge.net/projects/mygeneration/
In this page you find the templates that you need to run with the
softwarehttp://www.mygenerationsoftware.com/TemplateLibrary/Archives/?query=nhibernate
After you have this in the mygeneration tool you only connect to your DB and it will generated for you
Unfortunately, you can't have a polymorphic structure in a component. But I'm acutally not sure if you need it.
The following code is straight from my head, so it certainly has errors or missing things and wouldn't compile. But it should show the direction:
public class ReportRow
{
public int Id { get; private set; }
public IList<IReportValue> Values { get; private set; }
}
public interface IReportValue
{
public int Id{ get; set; }
public object UntypedValue { get; }
}
public abstract class ReportValue<T> : IReportValue
{
public int Id{ get; set; }
public T Value { get; set; }
public object UntypedValue { get { return Value; } }
}
public class ReportLongValue : ReportValue<long> {}
public class ReportStringValue : ReportValue<string> {}
public class ReportDateValue : ReportValue<DateTime>{}
Mapping:
<class ReportRow>
<id ...>
<bag name="Values" >
<key column="RowNumber"/>
<one-to-many class="IReportValue"/>
</bag>
</class>
<class name="IReportValue" abstract="true">
<id ...>
<subclass name="ReportLongValue">
<property name="Value" column="LongValue"/>
</subclass>
<subclass name="ReportStringValue">
<property name="Value" column="StringValue"/>
</subclass>
<subclass name="ReportDateValue">
<property name="Value" column="DateValue"/>
</subclass>
</class>