NHibernate 3或4是否与Entity Framework的“Include”方法等效,它采用字符串参数而不是llambda?我想在NHibernate中做这样的事情:
Contact contact =
context.Contacts.Include("SalesOrderHeaders.SalesOrderDetails")
.FirstOrDefault();
我遇到了来自this post的代码,它在一个很酷的循环中使用“Fetch”,但这只处理作为主要对象的第一级子对象的对象,而上面的EF代码却出现故障2个级别,不需要强烈类型的llambdas。
public IQueryable<T> All<T>(params Expression<Func<T, Object>> [] fetchPaths)
{
var queryable = this.session.Query<T>();
foreach (var fetchPath in fetchPaths)
{
queryable = queryable.Fetch(fetchPath);
}
return queryable;
}
答案 0 :(得分:3)
NHibernate有第二个方法叫做ThenFetch。你必须写
this.session.Query<T>()
.Fetch(x => x.Property)
.ThenFetch(x => x.SubProperty);
答案 1 :(得分:0)
似乎有几种方法可以解决我的问题。
选项1:以以下形式动态构建HQL:
from Contacts t0
left join fetch t0.SalesOrderHeaders t1
left join fetch t1.SalesOrderDetails t2
选项2:使用NHibernate的ICriteria.SetFetchMode。这可以处理基于字符串的连接,这非常有用,并且比我的目的更容易使用HQL方法。这是我最后编写的代码(改编自this post)。我希望它对别人有帮助。 &#34; GetPathsToUse&#34;方法是我尝试使用Entity Framework样式包含路径。所以,如果我想提供&#34; SalesOrderHeaders.SalesOrderDetails&#34;作为唯一的途径,该方法将添加&#34; SalesOrderHeaders&#34;第一个&#34; SalesOrderHeaders.SalesOrderDetails&#34;让NH很开心。
// This also uses ICriteria, but adds some logic to auto-handle paths to reduce the number of paths needed to pass in to match how
// EntityFramework works e.g. if one path is passed in for OrderInputs.Input, this method will call SetFetchMode twice, once for OrderInputs and again for OrderInputs.Input
public T GetByIdSetFetchModeEFStyle(Guid id, ISession session, params string[] includePaths)
{
ICriteria criteria = session.CreateCriteria<T>();
if (includePaths != null && includePaths.Length > 0)
{
// NHibernate requires paths to be supplied in order. So if a path "OrderInputs.Input" is supplied, we must make
// 2 separate calls to SetFetchMode, the first with "OrderInputs", and the second with "OrderInputs.Input".
// EntityFramework handles this for us, but NHibernate requires things to be different.
List<string> pathsToUse = this.GetPathsToUse(includePaths);
foreach (string path in pathsToUse)
{
criteria.SetFetchMode(path, FetchMode.Eager);
}
}
return criteria
// prevent duplicates in the results
.SetResultTransformer(Transformers.DistinctRootEntity)
.Add(Restrictions.Eq(typeof(T).Name + "Id", id)).UniqueResult<T>();
}
private List<string> GetPathsToUse(string[] includePaths)
{
var nhPaths = new List<string>();
foreach (string path in includePaths)
{
if (!path.Contains(".") && !nhPaths.Contains(path))
{
// There is no dot in the path - just add it if it hasn't been added already
nhPaths.Add(path);
}
else
{
// We have a dot e.g. OrderInputs.Input. We need to add "OrderInputs" before "OrderInputs.Input"
string[] pathParts = path.Split(".".ToCharArray());
// Add any missing ancestors of the current path prior to adding the path
for (int p = 1; p <= pathParts.Length; p++)
{
string requiredPath = string.Join(".", pathParts.Take(p).ToArray());
if (!nhPaths.Contains(requiredPath))
{
nhPaths.Add(requiredPath);
}
}
}
}
return nhPaths;
}