Mapping a column multiple times in Nhibernate - 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 }
}

Related

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>

Map a column multiple times

I have a rather odd requirement in my fluent hibernate maps. I have an table(A) which has a compound foreign key relationship with another table(B). In the mapping for table A I would like to have both the object created from table B and access to the individual attributes of A which define the key. Is there any way to do that? I seem to get index out of range exceptions if I map the column twice.
I cannot just explore B for the attributes because the row in table B may not exist. I am painfully aware that there are some significant smells in the structure with which I'm dealing. Such is the fate of those who deal with legacy systems.
It's kinda possible, by hacking around a little.
We're going to define a domain that with a fake collection that we'll use to retrieve the single related element, if found:
public class Foo
{
public virtual BarKey BarKey { get; set; }
public virtual Bar Bar { get { return Bars.SingleOrDefault(); } }
protected virtual ICollection<Bar> Bars { get; set; }
}
public class Bar
{
public virtual BarKey Id { get; set; }
}
//this class must override Equals and GetHashcode. Implementation not shown.
public class BarKey
{
public virtual int X { get; set; }
public virtual int Y { get; set; }
}
The BarKey component contains the properties that are part of the key.
Now, the mapping:
<class name="Foo">
<id ...><generator .../></id>
<component name="BarKey">
<property name="X" />
<property name="Y" />
</component>
<bag name="Bars" inverse="true">
<key property-ref="BarKey">
<column name="X"/>
<column name="Y"/>
</key>
<one-to-many class="Bar"/>
</bag>
</class>
<class name="Bar">
<composite-id name="Id">
<key-property name="X" />
<key-property name="Y" />
</composite-id>
</class>
The property-ref attribute there tells NH to match those columns in Bar against the BarKey property of Foo instead of its Id.

Saving child collections with NHibernate

I am in the process or learning NHibernate so bear with me.
I have an Order class and a Transaction class. Order has a one to many association with transaction. The transaction table in my database has a not null constraint on the OrderId foreign key.
Order class:
public class Order {
public virtual Guid Id { get; set; }
public virtual DateTime CreatedOn { get; set; }
public virtual decimal Total { get; set; }
public virtual ICollection<Transaction> Transactions { get; set; }
public Order() {
Transactions = new HashSet<Transaction>();
}
}
Order Mapping:
<class name="Order" table="Orders">
<cache usage="read-write"/>
<id name="Id">
<generator class="guid"/>
</id>
<property name="CreatedOn" type="datetime"/>
<property name="Total" type="decimal"/>
<set name="Transactions" table="Transactions" lazy="false" inverse="true">
<key column="OrderId"/>
<one-to-many class="Transaction"/>
</set>
Transaction Class:
public class Transaction {
public virtual Guid Id { get; set; }
public virtual DateTime ExecutedOn { get; set; }
public virtual bool Success { get; set; }
public virtual Order Order { get; set; }
}
Transaction Mapping:
<class name="Transaction" table="Transactions">
<cache usage="read-write"/>
<id name="Id" column="Id" type="Guid">
<generator class="guid"/>
</id>
<property name="ExecutedOn" type="datetime"/>
<property name="Success" type="bool"/>
<many-to-one name="Order" class="Order" column="OrderId" not-null="true"/>
Really I don't want a bidirectional association. There is no need for my transaction objects to reference their order object directly (I just need to access the transactions of an order). However, I had to add this so that Order.Transactions is persisted to the database:
Repository:
public void Update(Order entity)
{
using (ISession session = NHibernateHelper.OpenSession()) {
using (ITransaction transaction = session.BeginTransaction()) {
session.Update(entity);
foreach (var tx in entity.Transactions) {
tx.Order = entity;
session.SaveOrUpdate(tx);
}
transaction.Commit();
}
}
}
My problem is that this will then issue an update for every transaction on the order collection (regardless of whether it has changed or not).
What I was trying to get around was having to explicitly save the transaction before saving the order and instead just add the transactions to the order and then save the order:
public void Can_add_transaction_to_existing_order()
{
var orderRepo = new OrderRepository();
var order = orderRepo.GetById(new Guid("aa3b5d04-c5c8-4ad9-9b3e-9ce73e488a9f"));
Transaction tx = new Transaction();
tx.ExecutedOn = DateTime.Now;
tx.Success = true;
order.Transactions.Add(tx);
orderRepo.Update(order);
}
Although I have found quite a few articles covering the set up of a one-to-many association, most of these discuss retrieving of data and not persisting back.
Many thanks,
Ben
You need to set the cascade attribute on your mapping so that persistence is cascaded to the child objects:
<set name="Transactions" table="Transactions" lazy="false" inverse="true" cascade="all-delete-orphan">
Your Order object should have an AddTransaction method that sets the parent reference on the child. Something like:
public void AddTransaction(Transaction txn)
{
txn.Order = this;
Transactions.Add(txn);
}
This will cause the Transaction object to be persisted when the Order is persisted. You can expose the Order property on Transaction with the internal modifier so that it's not publicly visible.

NHibernate.Linq - Custom/Calculated property expression

How can a domain object include a property that calculates a value from other database mapped properties so that the calculated property can be used in both the domain object instance and the db level by nhibernate.linq.
I would like to be able to use the property when working with the object directly:
Console.WriteLine(Entity.Calculated.ToString());
And when working with nhibernate.linq
var q = from e in session.Linq<Entity>()
where e.Calculated > 0
select e;
You need to duplicate the logic in the class and the mapping. Here's an example:
Class:
public class Invoice
{
public virtual int Id { get; protected set; }
public virtual decimal Amount { get; set; }
public virtual decimal Paid { get; set; }
public virtual decimal Balance
{
get { return Amount - Paid; }
}
}
Mapping:
<class name="Invoice">
<id name="Id">
<generator class="hilo"/>
</id>
<property name="Amount"/>
<property name="Paid"/>
<property name="Balance" formula="Amount - Paid" access="readonly"/>
</class>
Now you can use Linq and query on Invoice.Balance

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>