Есть ли способ в NHibernate проверить, существует ли объект в базе данных без необходимости загрузки/загрузки объекта?
Проверить, существует ли объект в базе данных без загрузки объекта с помощью NHibernate
Ответ 1
Может всегда делать счет.
Я использую DetachedCriteria, поэтому у меня было бы что-то вроде:
var criteria = // some criteria that will identify your object
var result = criteria
.GetExecutableCriteria(Session)
.SetProjection(Projections.RowCountInt64())
.UniqueResult();
return result > 0;
Ответ 2
Вы можете использовать один из следующих 3 запросов (или вы можете использовать Criteria API Projections.RowCountInt64() из ответа Дэвида):
bool exist = session.Query<Employee>()
.Any(x => x.EmployeeID == 1);
bool exist = session.QueryOver<Employee>()
.Where(x => x.EmployeeID == 1)
.RowCount() > 0;
bool exist = session.Query<Employee>()
.Count(x => x.EmployeeID == 1) > 0;
Просто имейте в виду, что Any - это худший из этих трех, потому что он извлекает сущность. Здесь создается sql-запрос:
exec sp_executesql N'select TOP (1) employee0_.EmployeeID as EmployeeID0_, employee0_.Name as Name0_ from Employee employee0_ where [email protected]',N'@p0 int',@p0=1
exec sp_executesql N'SELECT count(*) as y0_ FROM Employee this_ WHERE this_.EmployeeID = @p0',N'@p0 int',@p0=1
exec sp_executesql N'select cast(count(*) as INT) as col_0_0_ from Employee employee0_ where [email protected]',N'@p0 int',@p0=1
Ответ 3
Поэтому я позволю себе провести несколько тестов с вашими примерами @Jamie Ide @Darius Kucinskas @Dmitry
Итак:
var exists = session
.CreateQuery("select 1 from Widget where _color = 'green'")
.SetMaxResults(1)
.UniqueResult<Int32?>()
.HasValue;
в моем случае было на 18% быстрее, чем
bool exist = session.Query<Employee>()
.Any(x => x.EmployeeID == 1);
14% чем
bool exist = session.Query<Employee>()
.Count(x => x.EmployeeID == 1) > 0;
и 8%
bool exist = session.QueryOver<Employee>()
.Where(x => x.EmployeeID == 1)
.RowCount() > 0;
Так что, на мой взгляд, даже если жестко закодированный запрос самый быстрый, то
bool exist = session.QueryOver<Employee>()
.Where(x => x.EmployeeID == 1)
.RowCount() > 0;
- лучший вариант из-за хороших привычек и четкости кода
Ответ 4
Чтобы расширить отличный ответ Дария Кучинскаса, вы можете избежать выборки объекта с помощью Select:
bool exist = session.Query<Employee>()
.Where(x => x.EmployeeID == 1)
.Select(x => x.EmployeeID)
.Any();
Как уже упоминалось, производительность запроса должна быть одинаковой, но я ожидаю, что это уменьшит сетевой трафик.
Ответ 5
Я думаю, вы ищете это...
var fooExists = session.Query<Foo>().Any(f => /*condition*/);
Ответ 6
var exists = 1 == session.CreateQuery("select 1 from MyEntity where Property = :value")
.SetValue("value", xxx)
.UniqueResult<Int32?>();
Ответ 7
На основе Ricardo ответ кажется самым эффективным способом проверить, существует ли объект с использованием HQL. Он не выполняет COUNT и не загружает объект без необходимости:
var exists = session
.CreateQuery("select 1 from Widget where _color = 'green'")
.SetMaxResults(1)
.UniqueResult<Int32?>()
.HasValue;
Он генерирует этот SQL (обратите внимание, что это SQLite, поэтому LIMIT вместо TOP)
select
1 as col_0_0_
from
Widgets
where
Color='green' limit 1;
Ответ 8
Вы можете попробовать:
public virtual T FindById<T>(int id)
{
return session.Get(typeof(T), id));
}
Ответ 9
Я создал метод расширения из ответов выше. Я предпочитаю использовать любую версию, но при выборе Select для первичного ключа будет возвращаться один и тот же объем данных в зависимости от типа первичного ключа.
public static bool Exists<TModel, TKey>(
this IQueryable<TModel> query, Expression<Func<TModel, TKey>> selector, TKey id)
where TKey : class
{
return query
.Select(selector)
.Any(x => x == id);
}
public static Task<bool> ExistsAsync<TModel, TKey>(
this IQueryable<TModel> query, Expression<Func<TModel, TKey>> selector, TKey id)
where TKey : class
{
return query
.Select(selector)
.AnyAsync(x => x == id);
}