0

To focus on the question here, we can say that I have one database layer and one application layer. So for the application to get access to the database I have to go through the database layer (of course).

Now the thing is that I want to write my queries using LINQ. And I could go two different paths here. One way [A] would be to create about 300 individual functions in the DBLayer, and call them from the Application (eg. GetAllUsers()).

OR [B] the DBLayer could more or less just offer a DBContext and then I can run the LINQ queries from the Application Layer (DBContext.GetAll<Users>().Where(x => x...).

I think that the [B] path would be more appealing, or at least less annoying since it wouldn't be so filled up with small functions. But what would you say?


However the problem with the [B] path is that, if I can avoid it I don't want to have a reference to NHibernate in the Application, but I don't seem to get access to the LINQ for NHibernate functions without referencing it. Is there a good solution to this?

Markus
  • 3,297
  • 4
  • 31
  • 52

2 Answers2

4

Option A with the mention what you don't need to create 300 functions, you need to create as many as required by the app needs. And some functions can get a Criteria which reduces the nubmer of functions.

The most important things is that all those functions will return app objects and NOT persistence objects, thus keeping the rest of the app decoupled form the persistence. Of course, the business/ui objects shouldn't know about NH either.

MikeSW
  • 16,140
  • 3
  • 39
  • 53
2

The solution with LINQ (B) is of course preferable (in comparison with 300 individual functions described in solution A)

And in fact is very easy to do. Your Data layer will just publish the today's standard: IQueryable.

The native NHibernate LINQ provider will do that for you:

var query = session.Query<TEntity>()

is in fact returning the a var query which is IQueryable<TEntity>

So the Data layer contaract (interface IDao...) could be like this (below is the implementation)

public virtual IQueryable<MyEntity> GetQueryable()
{
    var session = ....
    return sesion.query<MyEntity>();
}

In this case, no upper layer will ever notice, that it is working with NHibernate. And could in fact in some cases recieve results of a different IQueryable provider

EXTEND:

I would like also to append one (I even would say controversial) link, to Ayende block post: The DAL should go all the way to UI

A cite:

...My current approach is quite different. I define queries, which contains the actual business logic for the query, but I pass that query onward to higher levels of my application. Any additional processing on the query (projections, paging, sorting, etc) can be done. In that way, my queries are closed for modification and open for extension, since they can be further manipulated by higher level code...

While Ayende in general is not (at least at time of writing this article: Don’t castrate your architecture a fan of data, business, service layer... the logcic above is similar:

Pass the query (IQueryable) to upper layers. Apply some custome filters if needed (restrict the result more), but let the Client application (user) to work with it, to query your API

Radim Köhler
  • 122,561
  • 47
  • 239
  • 335
  • This means the app will always require something implementing IQueryable and the same **Persistence** entities as NH. Now, _WHY_ the rest of the app should tell the Persistence how to do its work (building queris and such)? – MikeSW Jan 31 '14 at 09:08
  • @MikeSW Who should build the query: Data layer? Or the Client i.e. User? if you know the answer, you know that the data layer should be responsible only for correct transformation of queries and changes into SQL Statements (read and write) – Radim Köhler Jan 31 '14 at 09:09
  • The Data layer builds the query because building a query is a persistence detail. The Client tells *what* not *how* – MikeSW Jan 31 '14 at 09:12
  • Obviously you @MikeSW do build the queries on the data layer. Usually the queries are coming from a User, via Client application. In a MS world - currently very preferred scenario - is: Client app can build the ODAta query via URL, it is directly converted into query over IQueryable statement. While this is too much MS... the answer is still the same, Data layer will never create queries... the **user** does – Radim Köhler Jan 31 '14 at 09:14
  • In order to build a query you must know the db schema, a persistence detail. Some data is fit for relational storage, other is better for a key-value store.While it doesn't mean you should use different db engines, it means that for some model you need to build queries, for others no. These are all DAL details and the BL or UI shouldn't know them. So if you want proper deocupling, you keep the building of queries in DAL, else don't bother to structure the app in the first place. You either respect SoC or not. – MikeSW Jan 31 '14 at 09:35
  • Pleas, try to step out from the DATA Layer. Think in the IQueryable. In the LINQ. If you will observe OData (MS standard, pushed hardly on the market) you will see that it does the standard. What you'd expect, even against the LDAP or XML. that is the trick of pssing the IQueryable UP – Radim Köhler Jan 31 '14 at 09:36
  • About Ayende, don't forget he promotes/sells a database engine and like MS he would love if your app is tightly coupled to his product – MikeSW Jan 31 '14 at 09:37
  • @MikeSW. Can we make a deal? Youd do not agree with the above. I do fully respect that. I really do. Good luck with NHibernate anyway ;) – Radim Köhler Jan 31 '14 at 09:38
  • I'm stepping OUT of the DAL but I keep everything related to persistence in there (proper architecture, Separation of Concerns). I don't think in IQueryable because it's an implementation detail and thus a leaky abstraction. And IQueryable is no 'standard' – MikeSW Jan 31 '14 at 09:41
  • I agree to disagree and I don't use NH nor EF :) – MikeSW Jan 31 '14 at 09:42
  • I used to think `repository` pattern was cool but ended up leaking IQueryable everywhere, hell I even leaked the `session` so I could get the goodness from `session.Load`. Personally I am ditching the repository layers and embracing NH in my app... I would say though that one way is not better than the other, but are testable, its what you are prepare to live with that counts. – Rippo Jan 31 '14 at 11:02
  • 1
    @Rippo I like your comment, I really do. The question about "Architecture" are simply personal, and not as easy as the "why I am getting 1 + N selects" ;). Not fighting for this approach. My experience says: The more flexible independent Data layer you have, returning POCO (http://stackoverflow.com/a/13632872/1679310) the more flexible upper layers. And honestly I did not mess it up until now! ;) ;) My sessions are working well ... and I do care about data on data layer, rules on busines layer, and queries on a Client... anyhow, not easy answers about architecture, right? ;) – Radim Köhler Jan 31 '14 at 11:09
  • 1
    No its a topic best left to debate over a pint of beer :) – Rippo Jan 31 '14 at 11:13
  • 1
    Actually there's nothing to debate. Want to decouple app from all persistence -> use proper repository pattern. Just want to access the db in a oop fashion from ANYWHERE in the app -> use directly the ORM. But using directly the ORM (or the leaky IQueryable - don't bother) should be done AWARE that your app is VERY tight coupled to persistence. For a lot of apps you don't need more. For whatever solution you choose you need to understand the trade offs. – MikeSW Jan 31 '14 at 11:22
  • 1
    Sounds like you made your mind up, my `debate` would be to talk about the trade offs, so yes its `a topic best left to debate over a pint of beer` ;) – Rippo Jan 31 '14 at 13:10