开发者

Complex taxonomy ORM mapping - looking for suggestions

开发者 https://www.devze.com 2023-02-10 02:30 出处:网络
In my project (ASP.NET MVC + NHibernate) I have all my entities, lets say Documents, described by set of custom metadata. Metadata is contained in a structure that can have multiple tags, categories e

In my project (ASP.NET MVC + NHibernate) I have all my entities, lets say Documents, described by set of custom metadata. Metadata is contained in a structure that can have multiple tags, categories etc. These terms have the most importance for users seeking the document they want, so it has an impact on views as well as underlying data structures, database querying etc.

From view side of application, what interests me the most are the string values for the terms. Ideally I would like to operate directly on the collections of strings like that:

class MetadataAsSeenInViews
{
    public IList<string> Categories;
    public IList<string> Tags;
    // etc.
}

From model perspective, I could use the same structure, do the simplest-possible ORM mapping and use it in queries like "fetch all documents with metadata exactly like this".

But that kind of structure could turn out useless if the application needs to perform complex database queries like "fetch all documents, for which at least one of categories is IN (cat1, cat2, ..., catN) OR at least one of tags is IN (tag1, ..., tagN)". In that case, for performance reasons, we would probably use numeric keys for categorie开发者_开发问答s and tags.

So one can imagine a structure opposite to MetadataAsSeenInViews that operates on numeric keys and provide complex mappings of integers to strings and other way round. But that solution doesn't really satisfy me for several reasons:

  • it smells like single responsibility violation, as we're dealing with database-specific issues when just wanting to describe Document business object
  • database keys are leaking through all layers
  • it adds unnecessary complexity in views
  • and I believe it doesn't take advantage of what can good ORM do

Ideally I would like to have:

  • single, as simple as possible metadata structure (ideally like the one at the top) in my whole application
  • complex querying issues addressed only in the database layer (meaning DB + ORM + at less as possible additional code for data layer)

Do you have any ideas how to structure the code and do the ORM mappings to be as elegant, as effective and as performant as it is possible?


I have found that it is problematic to use domain entities directly in the views. To help decouple things I apply two different techniques.

Most importantly I'm using separate ViewModel classes to pass data to views. When the data corresponds nicely with a domain model entity, AutoMapper can ease the pain of copying data between them, but otherwise a bit of manual wiring is needed. Seems like a lot of work in the beginning but really helps out once the project starts growing, and is especially important if you haven't just designed the database from scratch. I'm also using an intermediate service layer to obtain ViewModels in order to keep the controllers lean and to be able to reuse the logic.

The second option is mostly for performance reasons, but I usually end up creating custom repositories for fetching data that spans entities. That is, I create a custom class to hold the data I'm interested in, and then write custom LINQ (or whatever) to project the result into that. This can often dramatically increase performance over just fetching entities and applying the projection after the data has been retrieved.

Let me know if I haven't been elaborate enough.


The solution I've finally implemented don't fully satisfy me, but it'll do by now.

I've divided my Tags/Categories into "real entities", mapped in NHibernate as separate entities and "references", mapped as components depending from entities they describe.

So in my C# code I have two separate classes - TagEntity and TagReference which both carry the same information, looking from domain perspective. TagEntity knows database id and is managed by NHibernate sessions, whereas TagReference carries only the tag name as string so it is quite handy to use in the whole application and if needed it is still easily convertible to TagEntity using static lookup dictionary.

That entity/reference separation allows me to query the database in more efficient way, joining two tables only, like select from articles join articles_tags ... where articles_tags.tag_id = X without joining the tags table, which will be joined too when doing simple fully-object-oriented NHibernate queries.

0

精彩评论

暂无评论...
验证码 换一张
取 消