简体   繁体   中英

NHibernate generic repository without LINQ extension?

I'm looking for answers from a few days ago with no results.

I'm trying to make an implementation of an IRepository interface for generic repository using NHibernate. Here is the interface:

public interface IRepository<TEntity, TKey> where TEntity : BaseEntity
{
    TEntity GetById(TKey id);
    void Insert(TEntity entidad);
    void Update(TEntity entidad);
    void Delete(TEntity entidad);
    IQueryable<TEntity > Table { get; };
}

I know that there is an extension for the ISession interface, that brings the use of LINQ in my querys, but also I know that that plugin isn't working at 100% (I tested it but when I try to execute some complicated queryes, it thwows not implemented exception, so I can't use that plugin)

I'm using 100% the QueryOver function from the ISession, so.. Do you know any way to implement the IQueroOver function as IQueryable (without launch a "SELECT * " query)? If not, any others ideas for implement the generic repository pattern without use the LINQ extension?

Thank you very much

There's no such thing

Each person has their own definition of what features a 100% implemented LINQ provider should have. One might expect a LINQ provider to be able to translate String.Equals(String, String, StringComparison) to a SQL expression that uses the correct collation, but unless the programmers who created the LINQ provider programmed it to do so, it's not going to be able to do it. There is no end to the things we might want a LINQ provider to be able to do, so every LINQ provider has limitations. There is no such thing as 100% when it comes to LINQ providers. It is an unattainable concept. It is infinity.

Thus, it is important to...

  1. know the limitations of your LINQ provider, and
  2. know how to work around those limitations.

Limitations

With NHibernate, knowing the limitations is a bit harder than it should be, because there is currently no official documentation for the NHibernate LINQ provider. ( NH-2444 , patches are welcome!) However, you can figure some of it out just by knowing that this LINQ provider is built on top of HQL, so any limitations that HQL has, LINQ will have as well.

There is no NHibernate query syntax that directly supports performing arbitrary left outer joins on unrelated columns (besides Native SQL, of course). Queries in NHibernate are designed so that all of the information to perform a join is already stored in the mappings. After that, all you have to do is specify the relationship, such as order.Customer , and NHibernate knows which tables and columns to join together. You should be able to do arbitrary cross joins using HQL or LINQ, and then you could add a where clause to make it behave like an inner join, but no left outer join.

Since none of the query syntaxes directly support what you want to do, building a LINQ/QueryOver wrapper (as apposed to the existing LINQ/HQL wrapper, and probably just as complex to implement) will gain you nothing. You'll have to take the same steps to deal with this query whether you're using LINQ or QueryOver.

Workarounds

Since it is not possible for a LINQ provider to be complete, a well designed LINQ provider must be extensible. That way, if the LINQ provider doesn't natively support the functionality you need, it doesn't ruin your day. The NHibernate LINQ provider can be extended. See Giorgetti Alessandro's blog for more information.

But of course, before we go off writing LINQ provider extensions, we should check to see if there's a simpler way to solve the problem. A couple of possibilities come to mind:

The easiest way to handle this is to simply add the relationship to your NHibernate mappings, enabling you to leverage it in NHibernate queries (LINQ, or whatever). If the two columns are of incompatible data types, or require some kind of manipulation before you can perform the join, consider fixing the data and the schema in order to enable a smoother mapping.

Another option is to get creative with subqueries or use multiple queries to emulate what your desired join would do. For example, see one of my other answers :

... this LEFT OUTER JOIN can be simulated by combining the results of two separate queries - one to get the orders...

 var orders = session.Query<OrderHeader>() .Fetch(x => x.CreatedBy); 

... and another to get the people that have no orders:

 var peopleWithNoOrders = session.Query<Person>() .Where(p => !session.Query<OrderHeader>().Any(o => o.CreatedBy == p)); 

... because a left outer join is equivalent to an inner join plus additional results for non-matches. I don't know the details of the join you're trying to perform, but hopefully this will give you enough ideas to get started.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM