One to one self reference with Fluent NHibernate - fluent-nhibernate

Okay, I think I have a scenario I haven't seen elsewhere. I have a situation where I have an object type that needs to be able to be changed over time while retaining the history of the changes within the same table (as opposed to just in an audit table).
public class Item
{
public virtual int Id { get; set; }
public virtual ....
public virtual Item Replaces { get; set; }
public virtual Item ReplacedBy { get; set; }
}
I am stuck as to how to represent this in Fluent NHIbernate. In the database, I don't need both a Replaces and ReplacedBy field - I can get the info from just one of them. But I think I need both in my object for NHibernate to figure it out.
Currently, I have this, but it generates no database mappings at all:
mapping.HasOne(t => t.ReplacedBy).ForeignKey("Id").Class(typeof(Item));
As always, any thoughts greatly appreciated!

A HasOne or one-to-one relationship is a bit of a special relationship in NHibernate. It's (typically) an inferred relationship between two separate tables, whereby records that share a primary key value are associated. It's unlikely you'd be able to get a HasOne working for your situation. I have a post on my blog, I think you mean a many-to-one, sir, which goes into some of the misconceptions of HasOne relationships.
Instead you should look at using References, which is a many-to-one relationship, and does support self referential relationships.

Related

MVC EF Database first and SQL Many to many relationship

Source:
DictionaryTable:
DictID int
RUWordID int -> FK to RUWordsTable.RUWordID
ENWordID int -> FK to ENWordsTable.ENWordID
RUWordTable:
RUWordID int
Word string
ENWordTable:
ENWordID int
Word string
I want be able read/write data to table that uses following structure:
RUWord ENWord
Привет Hello
...
What the best option in terms of speed and easy data access from MVC views to do what i want. As per my understanding there is options to create SQL view and use it (but not sure about possible INSERTS of data). Or just create the same but using Entity Framework in Visual Studio designer.
Basically one word could be transalted differently (have several entries in other table). My goal to find a way how to add words to dictionary with automatic inserts (when source or translation not found add it to reference table, if found - just use existing entry)
It depends much on the amount of data you need to read in one go. If you want to look up translations of one or a few words an Entity Framework model will do a perfect job. If you need to fetch massive amounts of data a view or stored procedure will be better. But I don't expect the latter to happen. In an MVC view you'll probably use paging.
As for inserting data EF will be a viable choice. You already have a junction table defined (DictionaryTable). You could set up EF in a way that the junction table is transparent:
class RuWord
{
public int Id { get; set; }
public string Word { get; set; }
public ICollection<EnWord> EnWords { get; set; }
}
class EnWord
{
public int Id { get; set; }
public string Word { get; set; }
public ICollection<RuWord> RuWords { get; set; }
}
(supposing you'd work code-first)
In data entry you can add a new Russian word to the RussianWords DbSet of the context and add new or existing English words to the word's EnWords collection and call SaveChanges(). EF will insert the words and the appropriate records in the junction table (having both foreign keys as its composite primary key).
But... In real life I hardly ever see a pure junction table. I bring this in because in your case I can hardly imagine that just registering the associations between Russian and English words will be sufficient. Are you not (at least) going to need some degree of preference? Like there are more translations of the word "date", but the preferred one would be the calendar thing (unless you're working for a dating site, but even then...). Anyway, if there is something you want to record about the association you need to map the junction table explicitly and create the association records will all their details in code.
I hope this gives some directions.
Edit (after your comment)
If you use an explicit junction entity (i.e. a class that corresponds with the junction table). This entity can have the two properties EnWord and RuWord as references to the two tables mentioned above. Data entry would imply creating a new DictionaryTable instance and setting its properties (which can be new or existing words).

NHibernate: Add entity to many-to-many collection by id only

I'm looking for a shortcut. I have some NH entities with a many-to-many relationship. Something like this:
public class Customer : EntityBase<Customer>
{
public virtual IList<Category> Categories { get; set; }
}
public class Category : EntityBase<Category>
{
public virtual IList<Customer> Customers { get; set; }
}
Bear in mind this is a very simple depiction, so resist the temptation to suggest I not use a many-to-many arrangement or that I should use a value type or anything like that.
On the DB side, this relationship is accomplished via a separate table with two columns - Customer_Id and Category_Id.
I'd really like to be able to add an existing Category to a Customer without having to retrieve the full entity from the database. Maybe something like this:
customerEntity.Categories.Add(new Category { Id = 2 });
The reason for this is that the application is an ASP.NET MVC app and I'm using ViewModels for my views. These Customer ViewModels end up with a List<int> for the category selections, and when I go to map that ViewModel to the corresponding Customer entity, I'd love to just be able to suck those category IDs into the Categories list without having to hit the database to retrieve them first.
Part of the reason I want to be able to do this is that I'd like to minimize database calls, but I also would like to have my mapper class be able to create the Customer entity without having to make calls to my service layer to go asking for other objects...that seems like bad design. I'd also like to avoid having to add another layer to call the mapper then do the other mapping stuff that pulls entities from the repository (which is itself accessed through a domain service layer).
I checked out idbag, but for one I'm using Fluent NHibernate and it doesn't support that construct, and for two from what I can glean from the docs that will give me a List<int> on the entity, and I'd still like to be able to access the full entity in those collections.
Am I asking too much out of NHibernate?
Use ISession.Load:
customerEntity.Categories.Add(session.Load<Category>(2));
Load will return a proxy and does not hit the database. You can access the ID property of the proxy without hitting the database, but NHibernate will load the proxy if you access any other properties.

What is the best way to retrieve/save log entries linked to other entities through NHibernate?

Disclaimer: I'm outlining simplified picture to emphasize main point of my question.
The application I'm working on maintains a set of resources. We have a corresponding table and mapped entity in NHibernate. Each resource identified by integer id. Also we have user table and corresponding entity to maintain user profiles.
We need to log user accesses to the application and retrieve access history. For repository class we have to introduce 2 methods:
IEnumerable GetUserLog(User user) to retrieve user access history order by date in descending order and
void WriteLogEntry(User user, Resource resource) to write new entry
I have tried to simply define LogEntry entity as following:
public class LogEntry
{
public virtual User User {get; set;}
public virtual Resource Resource {get; set;}
public virtual DateTime Date {get; set;}
}
and map it using Fluent NHibernate as usually. To retrieve/update log entries we can simply use
Session.Query<LogEntry>().Where(entry => entry.User = currentUser).OrderByDesc(entry => entry.Date)
Session.Save(new LogEntry() {
User = currentUser,
Resource = resource,
Date = DateTime.Now
})
This is the most convenient way to deal with this issue for us.
Problem
The problem is that NHibernate requires id mapping. We have to use composite id here and the only option is to map User, Resource and Date columns because only this combination provides uniqueness. Also in case of composite id we have to override Equals and GetHashCode and all this seems to be overkill for such a simple task. Another problem that lazy loading cannot be used for id fields and it's too much as well. We do not want to load all related Resource entities in advance.
Another possible solution is to define plain class, not entity and then use SetResultTransformer(Transformers.AliasToBean()) to retrieve results. In that case we have to construct queries manually, retrieve related entities manually and this way it's not better in general then dealing with raw connection.
I would like to ask expert opinion because I'm confident people around had similar experience and can help. Thanks in advance.
P.S. This is ASP.NET MVC application using NHibernate 3 (+ Fluent). Log information will be used to display last 5-10 resources user accessed.
have you considered introducing an Id field for LogEntry table as well?
many DBAs will recommend it and it seems like the easiest solution.

Should I strip FKs out of my domain model?

I'm starting a new project and plan on using nhibernate. I'm struggling with whether or not I should keep my domain model clean of persistence information by leaving out foreign keys. I keep feeling like some of my "model" isn't really necessary and that performance is going to be an issue. For example:
In my db I have the following table:
Posting
Id
StatusId
...
Which has an FK relationship with this table:
PostingStatus
Id
Name
In my model I've defined 2 classes:
class Posting
{
virtual int Id { get; set; }
virtual PostingStatus Status { get; set; }
// ..
}
class PostingStatus
{
virtual int Id { get; set; }
virtual string Name { get; set; }
}
Does PostingStatus belong in my model? and in cases where I know the FK ahead of time, like updating a posting after a submit, isn't it a pretty heavy performance hit (or just useless work) to have nhibernate fetch a PostingStatus instance instead of just setting a FK?
I'm pretty sure this issue has been discussed before but I keep finding bits an pieces of the discussion that have shotty relevance. Thoughts or resources on this issue would be greatly appreciated.
If the Domain Model requires relationships to be enforced then you need Foreign Keys.
Don't worry about performance until you actually have a performance problem.
What Mitch said. NHibernate was put together by people who thought about these issues thoroughly. Do what's right, worry about optimization when and if you have a problem.
(nhibernate's probably going to be fetching the posting sttaus from cache, anyway.)
Besides, nhibernate, depending on how you set it up, may need FK constraints to map your database to your objects.
If PostingStatus is an domain entity, you should keep it. If it's not, remove it for that reason, not in an attempt to prematurely optimize.
In this very special case you might actually replace the entity PostingStatus with Enum. If you specify values for your enum properly they can map to a table and be enforced by FK.
And NH will not 'just cache' stuff. I'd suggest using 2nd level cache with lazy loading of PostingStatus heavily for this kind of situations.

NHibernate/ActiveRecord - Any way to map to a foreign key column only?

I'm using Castle ActiveRecord, but this question applies to NHibernate, too, since a solution that works with NHibernate should work for ActiveRecord. Anyway, what I have is an underlying table structure like this:
TableA -hasMany-> TableB
I have corresponding objects EntityA and EntityB. EntityA has an IList of EntityB objects. This part works fine. Now, I want EntityB to have some kind of reference back to EntityA. I know I can use the BelongsTo attribute on EntityB to give it an actual reference back to the full EntityA type, like:
[BelongsTo("tableAid")]
public EntityA Parent { get; set; }
But what I'd really like to do is:
[BelongsTo("tableAid")]
public int ParentId { get; set; }
So, EntityB would store only the ID of the parent object, not a reference to the actual object. This is a trivial example, but I have good reasons for wanting to go with this approach. In the application I'm working on, we have pages that display specific EntityB-like objects, and we'd like for those pages to include links (as in hyperlinks) to the corresponding parent pages. We can do that by using the first approach above, but that requires that the entire EntityA object be loaded when all I really need is the ID. It's not a huge deal, but it just seems wasteful. I know I can use lazy-loading, but again, that seems more like a hack to me...
I have tried flagging the foreign key with the [Property] attribute like so:
[Property]
public int ParentId { get; set; }
The problem with this approach is that EntityB.ParentId remains null when you do a EntityA.SaveAndFlush() on a new object tree. The correct value is being written to the database, and I can force the value back into EntityB.ParentId by doing an EntityA.Refresh(), but again, that seems like a bit of a hack.
Lazy loading is exactly what you want - and it's not a hack either, it's a well tested and baked in part of NHIbernate and an important tool when performance tuning any substantial NHibernate app.
If you were to mark your "parent" EntityA as lazy loaded, referring to EntityB.Parent.Id would not load EntityA at all (as behind the scenes NHIbernate has already loaded EntityA's id when loading EntityB) - thus letting you setup your links without incurring a performance penalty.
Just this:
[Property] public int ParentId { get; set; }
...assuming ParentId is the actual column name.
A couple of other comments.
First, you should consider lazy loading many-to-one properties anyway. If you eagerly load them, you must be aware of possible cascades of eager loads, which can make a serious performance hit. To do this you must mark all public members of the lazily loaded class as virtual.
Second, be aware that any time you have a one-to-many association with no corresponding relation from the child back to the parent, you must make the FK nullable in the database. That's because when NH creates new child items, it will insert it with the parent id null and then in a second step update it.