I have a class that I need to map that looks a bit like this
public class Foo
{
public string Name { get; set; }
// other stuff
public IDictionary<Bar, decimal> Bars { get; set; }
}
my question is how can I map this with NHibernate, I was thinking I can treat the dictionary as a HasMany, since I can recreate a Bar from a string, however it feels a bit crude and I wonder if there is a better way
cheers
<map name="Bars">
<key column="..." />
<map-key-many-to-many class="Bar" />
<element type="String" /><!--or decimal, or anything else-->
</map>
It depends what the decimal might be, but NHibernate does provide a <map> collection type specifically for Dictionary style mappings.
may be this would help:
nhibernate-mapping-map
Related
I have the below two classes:
public class Project
{
public virtual int ProjectId { get; set; }
public virtual string ProjectName { get; set; }
public virtual LegalEntity LegalEntity { get; set; }
}
and
public class LegalEntity
{
public virtual int LegalEntId { get; set; }
public virtual string Name { get; set; }
}
with mappings as:
<class name="Project" table="Project" dynamic-update="true">
<id name="ProjectId">
<generator class="native"/>
</id>
<property name="ProjectName" />
<many-to-one name="LegalEntity" column="LegalEntId" fetch="join" cascade="all-delete-orphan" />
</class>
and
<class name="LegalEntity" table="LegalEnt" dynamic-update="true">
<id name="LegalEntId">
<generator class="native"/>
</id>
<property name="Name" />
</class>
In database, Project table has a FK to LegalEntity's PK column. One Project will have only one legal entity. Different projects can have same legal entity. So thats the reason I have gone for many-to-one. Not sure if this is correct though.
Insert and update is working fine. But if I update a legal entity id in a project and that legal entity becomes orphan, I want it to be deleted. But its not happening. Am I wrong in understanding delete-all-orphan? If yes, how can I achieve this behaviour?
The many-to-one cascade does not support all-delete-orphan, see:
5.1.10. many-to-one
<many-to-one
...
cascade="all|none|save-update|delete" (4)
...
Also, it would be almost impossible to handle this feature by NHibernate's session. Because it does not have to be clear, that the referenced many-to-one is really orphan. There should be some farther checks in DB... there could be other places referencing this table row...
Suggestion: do it in your code as a part of the DAO or Business Facade implementation. Check if there are really no dependencies, and then issue explicit Delete()
EXTEND: Here is a QueryOver syntax to get a list of all "orphan" LegalEntity
// subquery
var subquery = QueryOver.Of<Project>()
.Select(x => x.LegalEntity.LegalEntId);
// just these legal entities, which are NOT used
var query = session.QueryOver<LegalEntity>()
.WithSubquery
.WhereProperty(y => y.LegalEntId)
.NotIn(subquery)
;
// orphans
var list = query
.List<LegalEntity>();
Now all-delete-orphan and delete-orphan have been implemented for many-to-one as you can see in this commit from Nov 19, 2014.
Those were not supported when the OP asked the questions or when Radim Köhler wrote his answer, but I think future visitors will appretiate the update.
The documentation is also updated and now says:
cascade="all|none|save-update|delete|delete-orphan|all-delete-orphan"
But the documentation is confusing now, because it still has the following note:
The cascade attribute permits the following values: all, save-update, delete, none.
So I've created a defect to fix that last part of the documentation.
My scenario is that I have a User class, and that class has to be extended with related data, but without being subclassed.
For example the user might have lots of different profile data: AddressProfileData, FavoritesProfileData, etc etc.
I have decided to go with an abstract class and many implementations, kind of like in this post: inheritance mapping
However, I can't find a way to ensure (using nhibernate and not programmatically) that each item, for example AddressProfileData occurs only once per user.
Is this possible? If not, is there another solution for this problem which is more proper? I feel that sharing a common abstract class is building my app around NHibernate, and not the other way round.
AddressProfileData and FavoritesProfileData are likely to share almost nothing common, except for the fact that they both are extra information you attach to a User, so I don't think it makes sense to make them part of some inheritance hierarchy. Instead, I would go with something like this:
public class User
{
// ... other properties ...
public virtual AddressProfileData Address { get; set; }
public virtual FavoritesProfileData Favorites { get; set; }
}
public class AddressProfileData
{
// ... other properties ...
public virtual User User { get; set; }
}
<class name="User">
<!-- ... other properties ... -->
<one-to-one name="Address" property-ref="User" />
<one-to-one name="Favorites" property-ref="User" />
</class>
<class name="AddressProfileData">
<!-- ... other properties ... -->
<many-to-one name="User" column="User_id" unique="true" not-null="true" />
</class>
create table AddressProfileData (
/* ... other columns ... */
User_id int not null,
unique (User_id),
foreign key (User_id) references User (Id)
);
I'm sure you can imagine what FavoritesProfileData looks like.
With this setup, you ensure that each type of profile data only occurs once per user, and you also don't wind up in a weird place where you have to test which type of ProfileData you're dealing with before you can do anything with it. You always know exactly what kind of profile data you're touching.
I don't like the idea of proxy and lazy loading. I don't need that. I want pure POCO. And I want to control loading associations explicitly when I need.
Here is entity
public class Post
{
public long Id { get; set; }
public long OwnerId { get; set; }
public string Content { get; set; }
public User Owner { get; set; }
}
and mapping
<class name="Post">
<id name="Id" />
<property name="OwnerId" />
<property name="Content" />
<many-to-one name="Owner" column="OwnerId" />
</class>
However if I specify lazy="false" in the mapping, Owner is always eagerly fetched.
I can't remove many-to-one mapping because that also disables explicit loading or a query like
from x in session.Query<Post>()
where x.Owner.Title == "hello"
select x;
I specified lazy="true" and set use_proxy_validator property to false. But that also eager loads Owner.
Is there any way to load only Post entity?
In short, it is not possible with out of box NH. But here is attempt at just, lazy loading without proxies
http://thinkbeforecoding.com/post/2009/02/07/Lazy-load-and-persistence-ignorance
Set the class User to lazy = false on the mapping
<class name="User" table="Users" lazy="false">
Remove this property <property name="OwnerId" />... to get the owner id you can use Owner.Id. This will not trigger a lazy load. Owner will only be loaded if you hit any property besides the id. To make it a flat/simple POCO, you can use projections and ResultTransformers.
Davy Brion - Must Everything be Virtual with NHibernate
nHibernate is giving the error : Custom type does not implement UserCollectionType: myApp.Domain.OrderLineCollection.
BindingList implements IList, so why is nHibernate trying to use UserCollectionType instead of IList?
public class OrderHeader
{
public virtual int OrderHeaderId { get; set; }
public virtual string OrderNumber { get; set; }
public virtual OrderLineCollection Line { get; set; }
}
public class OrderLineCollection : BindingList<OrderHeader> { }
public class OrderHeaderMap : ClassMap<OrderHeader>
{
public OrderHeaderMap()
{
WithTable("Orders");
Id(x => x.OrderHeaderId, "OrderId").GeneratedBy.Identity();
Map(x => x.OrderNumber);
HasMany(x => x.Line).WithKeyColumn("OrderHeaderId").AsList();
}
}
<list name="Line">
<key column="OrderHeaderId" />
<index />
<one-to-many class="myApp.Domain.OrderLine, myApp.Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</list>
NHibernate has it's own custom typed list which implements IList underneath.
I'm afraid you won't be able to use yours without creating nHibernate UserType.
But i might be wrong and would be glad to hear why. :)
You might want to check the XML that's created by fluentNHibernate - it's quite possible they take the type of the Line property and set it explicitly.
This should work if you don't set the type explicitly. I tried implementing a custom collection deriving from IList - and it worked when I didn't specify the type on the bag/list whatever in the mapping.
Ok, I did a quick test Arnis L. is right - it probably won't work without implementing UserCollectionType. In my experience, it's a pain to implement .
(somehow I remembered doing something like this but I guess my mind's playing tricks on me)
I look at the NHibernate source code and at least for PersistentBag and PersistentList NHibernate will instanciate a ArrayList object as the back end list, not a OrderLineCollection as one could thought. When you implement IUserColletionType there is a method who tells NHibernate what collection it should create, and also what Persistent collection Hibernate should use to sav. Take a look at this link might help a lot. But I still cant do Nhibernate work with BindingList.
Suppose I have this class:
public class GroceryListItem()
{
public GroceryList { get; private set; }
public GroceryListItem(GroceryList groceryList)
{
GroceryList = groceryList;
}
}
What is the NHibernate mapping file access strategy for this scenario? (i.e. <one-to-many name="GroceryList" column="XXX" access="?????" />)
It turns out the answer is pretty simple -- no special access is required. NHibernate is smart enough to work this out on its own. In other words, the code in my question works correctly with the following line in the mapping file:
<one-to-many name="GroceryList" column="XXX" />
Use access="readonly" in the newer versions, or create your own PropertyAccessor or use any of the other approaches described here:
http://blog.schuager.com/2008/12/nhibernate-read-only-property-access.html