Nhibernate: Conditional And Clause in QueryOver() - c#

this is my query:
var query = _session.QueryOver<CRMPhoneCall>();
if (filter.Subject != null)
{
query.JoinQueryOver<CRMPhoneCall_Subject>
(p => p.PhoneCall_Subject)
.JoinQueryOver(d => d.Subject)
.And(s => s.Id == filter.Subject.Id) //check filter.Subject.Id has value else The condition does not apply
.And(s => s.Parent == null) //check filter.OnlyMainSubject has true else The condition does not apply;
}
two separate if for check filter.Subject And filter.OnlyMainSubject does not work(duplicate instance in QueryOver)

var query = session.QueryOver<CRMPhoneCall>();
if (filter.Subject != null)
{
var subjectQuery = query.JoinQueryOver<CRMPhoneCall_Subject>(p => p.PhoneCall_Subject)
.Where(s => s.Subject == filter.Subject);
if (filter.OnlyMainSubject)
{
subjectQuery.JoinQueryOver(ps => ps.Subject)
.Where(s => s.Parent == null); //check filter.OnlyMainSubject has true else The condition does not apply;
}
}

Related

Dropping columns from a where clause can i use the ? operator

I cannot help but feel this is very slopy and there is more that I can do to cut this down.
public async Task<IActionResult> Index(int? id)
{
List<ClubMembers> clubs = new List<ClubMembers>();
Guid.TryParse(UserId.ToString().ToUpper(), out
Guid guidResult);
if (id == null)
clubs = await _context.ClubMembers.Where(w =>
w.isActive == true && w.isDeleted == false)
.Include(c => c.Role)
.Include(c => c.User)
.Where(w => w.isActive == true
&& w.isDeleted == false).ToListAsync();
else
clubs = await _context.ClubMembers.Where(w =>
w.ClubId == id && w.isActive == true && w.isDeleted
== false).Include(c => c.Role).Include(c => c.User)
.Where(w => w.isActive == true
&& w.isDeleted == false).ToListAsync();
ClubMembersViewModal clubMembersViewModal = new ClubMembersViewModal();
clubMembersViewModal.Clubusers = clubsMembers;
clubMembersViewModal.ClubInvitesViewModal = new ClubInvitesViewModel();
clubMembersViewModal.ClubInvitesViewModal.ClubId = ClubId;
clubMembersViewModal.ClubInvitesViewModal.FromMember = Email;
clubMembersViewModal.ClubInvitesViewModal.ToMember = "test#gmail.com";
return View(clubMembersViewModal);
}
As I am just removing the need for one column the w.ClubId == in the first query is their not a cleaner way of just removing the column from the one query at all seems sloppy to do it this way?.
Could I use the null check operation ? in some where as part of the where clause? I just want it to not filter ClubId if no id is passed.
You can use IQueryable<T> to construct your query step by step, like this.
IQueryable<ClubMembers> queryable = _context.ClubMembers
.Where(w => w.isActive == true && w.isDeleted == false)
.Include(c => c.Role).Include(c => c.User);
if (id != null)
queryable = queryable.Where(w => w.ClubId == id);
clubs = await queryable.ToListAsync();

Entity Framework Core LINQ query with multiple where clauses

I need some sample code for my project. I am working with EF CORE 2.1.1.
I created a function which accepts 3 parameters, inside that function I am executing a LINQ (lambda expression query), returning a list.
Here is my function :
public IEnumerable<Donneesource> GetAllSourcesFromBDD(DateTime PremierDateCom, DateTime DerniereDateCom, string Secteur)
{
try
{
//Récupération des données.
IEnumerable<Donneesource> RawDatas = _sourceDAL.Donneesource
.Where(ic => ic.EstCopieDestination == false)
.Where(s => PremierDateCom != DateTime.MinValue && s.SComPremierDate.Value.Date == PremierDateCom.Date)
.Where(s => DerniereDateCom != DateTime.MinValue && s.SComDerniereDate.Value.Date == DerniereDateCom.Date)
.Where(s => Secteur != string.Empty && s.SSectNom == Secteur)
.ToList();
return RawDatas;
}
catch(Exception)
{
return null;
}
}
By default I set DateTime params to DateTime.MinValue (PremierDateCom,DerniereDateCom) and string param to string.Empty (Secteur).
I am trying to create a single query with where clauses. I want to ignore the where clauses with default params. For example If PremierDateCom = DateTime.MinValue (or other params) then I want to ignore the where clauses if something I want to include my where clause in my query.
I don't want to create a query like this:
//Filtre
if (PremierDateCom != DateTime.MinValue)
RawDatas = RawDatas.Where(x => x.SComPremierDate.Value.ToShortDateString() == PremierDateCom.ToShortDateString());
//Filtre
if (DerniereDateCom != DateTime.MinValue)
RawDatas = RawDatas.Where(x => x.SComDerniereDate.Value.ToShortDateString() == DerniereDateCom.ToShortDateString());
//Filtre
if (Secteur != null)
RawDatas = RawDatas.Where(x => x.SSectNom == Secteur);
Assuming _sourceDAL.Donneesource gives you an IQueryable<T> then you should be building up your query by adding Where clauses inside an if statement. This is because an IQueryable will not run a query against the database until you materialise it, i.e. with a foreach or a .ToList(). So something like this:
IQueryable<Donneesource> RawDatas = _sourceDAL.Donneesource
.Where(ic => ic.EstCopieDestination == false)
.Where(s => PremierDateCom != DateTime.MinValue && s.SComPremierDate.Value.Date == PremierDateCom.Date)
.Where(s => DerniereDateCom != DateTime.MinValue && s.SComDerniereDate.Value.Date == DerniereDateCom.Date)
.Where(s => Secteur != string.Empty && s.SSectNom == Secteur);
if (PremierDateCom != DateTime.MinValue)
{
RawDatas = RawDatas.Where(x => x.SComPremierDate.Value.ToShortDateString() == PremierDateCom.ToShortDateString());
}
if (DerniereDateCom != DateTime.MinValue)
{
RawDatas = RawDatas.Where(x => x.SComDerniereDate.Value.ToShortDateString() == DerniereDateCom.ToShortDateString());
}
if (Secteur != null)
{
RawDatas = RawDatas.Where(x => x.SSectNom == Secteur);
}
//Now get the data from the database:
return RawDatas.ToList();
To avoid using many if statements you can also try the following:
IQueryable<Donneesource> RawDatas = _sourceDAL.Donneesource
.Where(ic => !ic.EstCopieDestination)
.Where(s => PremierDateCom != DateTime.MinValue ? s.SComPremierDate.Value.Date == PremierDateCom.Date : true)
.Where(s => DerniereDateCom != DateTime.MinValue ? s.SComDerniereDate.Value.Date == DerniereDateCom.Date : true)
.Where(s => Secteur != string.Empty ? s.SSectNom == Secteur : true);
You can use a conditional statement, and if the condition is not satisfied, pass true instead.

fluent nHibernate Restrictions.Not seems not be working properly

I have the association:
TableA 1 --- * TableB
I try to build a query, which returns me the list of the TableA items, whose ALL items (TableB) have a value in the column X and Y. But that query seems to be ignoring that not null condition in the X and Y column, why ?
Or, how to rebuild that query, maybe play with the subquery ?
TableA tabA = null;
TableB tabB = null;
var s = Session.QueryOver<TableA>(() => tabA)
.JoinAlias(() => tabB.TableBItems, () => tabB, JoinType.InnerJoin)
.Where(Restrictions.Conjunction()
.Add(() => tabA.SomeID == 123)
.Add(() => tabA.SomeNullableDate != null)
)
.Where(Restrictions.Not(
Restrictions.Conjunction()
.Add(() => tabB.X == null)
.Add(() => tabB.Y == null)
))
.List<TableA>();
use a subquery to filter out TableA elements having null values in tabB-Items
var subquery = QueryOver.Of<TableA>()
.JoinQueryOver(tabA => tabA.TableBItems)
.Where(tabB => tabB.X == null || tabB.Y == null)
.Select(Projections.Id());
var s = Session.QueryOver<TableA>()
.Where(tabA => tabA.SomeID == 123 && tabA.SomeNullableDate != null)
.WhereRestrictionOn(Projections.Id()).NotIn(subquery)
.JoinQueryOver(tabA => tabA.TableBItems)
.Where(tabB => tabB.X != null && tabB.Y != null)
.List<TableA>();

Union on empty Enumerable

I have function
public async Task<IQueryable<Document>> GetDocuments(...)
in which I search for documents under some given conditions. Some conditions can be skipped. At the end I perform union of these queries.
var documents = await documentService.GetDocuments(this, userId,
roleShowFullNumber, param.OrderColName(), param.SearchValue, filter);
var usersGroupsId = filter.UsersGroupsId;
if (usersGroupsId != null)
{
if (!usersGroupsId.Contains("All"))
{
IQueryable<Document> myDocs = Enumerable.Empty<Document>().AsQueryable();
if (usersGroupsId.Contains("myOrders"))
{
myDocs = documents.Where(x => x.OwnerId == userId || x.UserId == userId);
usersGroupsId = usersGroupsId.Where(x => x != "myOrders").ToArray();
}
IQueryable<Document> wards = Enumerable.Empty<Document>().AsQueryable();
if (usersGroupsId.Contains("wards"))
{
var relatedUserId = _db.Users.Where(x => x.Id == userId).Select(x => x.RelatedUserId).FirstOrDefault();
if (relatedUserId != null)
{
var myWards = _db.kh__Kontrahent.Where(x => x.kh_IdOpiekun == relatedUserId);
var myWardsUsers = _db.Users.Where(x => myWards.Any(w => w.kh_Id == (x.RelatedCustomerId == null ? -1 : x.RelatedCustomerId)));
wards = documents.Where(x => (myWardsUsers.Any(w => x.UserId == w.Id) || myWardsUsers.Any(w => x.OwnerId == w.Id)));
usersGroupsId = usersGroupsId.Where(x => x != "wards").ToArray();
}
}
IQueryable<Document> groups = Enumerable.Empty<Document>().AsQueryable();
if (usersGroupsId.Length > 0)
{
var usersGroups = _db.Groups.Where(x => usersGroupsId.Contains(x.Id.ToString()));
var usersList = usersGroups.Select(x => x.Users);
var users = usersList.SelectMany(x => x);
var usersId = users.Select(x => x.Id);
groups = _db.Documents.Where(x => (usersId.Any(u => u == x.OwnerId) || usersId.Any(u => u == x.UserId)));
}
documents = myDocs.Union(wards).Union(groups);
}
}
But if one of these partial queries is empty (was skipped) when I try obtain these documents in way shown below I got error.
var documentsPaginated = await documents.Skip(param.Start)
.Take(param.Length)
.ToListAsync();
Error: The source IQueryable doesn't implement IDbAsyncEnumerable.
How can I make this function to be able to skip some sub queries and then union all. I would prefer not to change function return value.
Try this, althought your code seems to have a massive amount of code smell...
public async Task<IQueryable<Document>> GetDocuments(...)
var documents = await documentService.GetDocuments(this, userId,
roleShowFullNumber, param.OrderColName(), param.SearchValue, filter);
var usersGroupsId = filter.UsersGroupsId;
if (usersGroupsId != null)
{
if (!usersGroupsId.Contains("All"))
{
IQueryable<Document> myDocs = null;
if (usersGroupsId.Contains("myOrders"))
{
myDocs = documents.Where(x => x.OwnerId == userId || x.UserId == userId);
usersGroupsId = usersGroupsId.Where(x => x != "myOrders").ToArray();
}
IQueryable<Document> wards = null;
if (usersGroupsId.Contains("wards"))
{
var relatedUserId = _db.Users.Where(x => x.Id == userId).Select(x => x.RelatedUserId).FirstOrDefault();
if (relatedUserId != null)
{
var myWards = _db.kh__Kontrahent.Where(x => x.kh_IdOpiekun == relatedUserId);
var myWardsUsers = _db.Users.Where(x => myWards.Any(w => w.kh_Id == (x.RelatedCustomerId == null ? -1 : x.RelatedCustomerId)));
wards = documents.Where(x => (myWardsUsers.Any(w => x.UserId == w.Id) || myWardsUsers.Any(w => x.OwnerId == w.Id)));
usersGroupsId = usersGroupsId.Where(x => x != "wards").ToArray();
}
}
IQueryable<Document> groups = null;
if (usersGroupsId.Length > 0)
{
var usersGroups = _db.Groups.Where(x => usersGroupsId.Contains(x.Id.ToString()));
var usersList = usersGroups.Select(x => x.Users);
var users = usersList.SelectMany(x => x);
var usersId = users.Select(x => x.Id);
groups = _db.Documents.Where(x => (usersId.Any(u => u == x.OwnerId) || usersId.Any(u => u == x.UserId)));
}
if(myDocs != null)
documents = documents.Union(myDocs);
if(wards != null)
documents = documents.Union(wards);
if(groups != null)
documents = documents.Union(groups);
}
}
It appears that ToListAsync can't be used interchangeably with linq, but only in an EF query.
Quote from MSDN
Entity Framework 6 introduced a set of extension methods that can be used to asynchronously execute a query. Examples of these methods include ToListAsync, FirstAsync, ForEachAsync, etc.
Because Entity Framework queries make use of LINQ, the extension methods are defined on IQueryable and IEnumerable. However, because they are only designed to be used with Entity Framework you may receive the following error if you try to use them on a LINQ query that isn’t an Entity Framework query.
The source IQueryable doesn't implement IDbAsyncEnumerable{0}. Only sources that implement IDbAsyncEnumerable can be used for Entity Framework asynchronous operations. For more details see http://go.microsoft.com/fwlink/?LinkId=287068.

can i make a this linq statement iteration from a collection in a single statement?

bool isExist = objCustomization.CustomSettings.Where(p => p.CustomizationType == selCustomizationType && p.CategoryID == selCategoryID).Any();
if (isExist)
{
chkFixLimit.Checked = objCustomization.CustomSettings.Where(p => p.CustomizationType == selCustomizationType && p.CategoryID == selCategoryID).FirstOrDefault().IsDefaultLimit;
}
else chkFixLimit.Checked = false;
Default value for boolean is false so you even don't need any conditions - just select first or default IsDefaultLimit value:
chkFixLimit.Checked =
objCustomization.CustomSettings
.Where(p => p.CustomizationType == selCustomizationType && p.CategoryID == selCategoryID)
.Select(p => p.IsDefaultLimit)
.FirstOrDefault();
UPDATE (answer for your comment) in case you have non-boolean value or default value (zero for integer) do not fit your requirements, with DefaultIfEmpty you can provide own default value if there is no items matching your condition:
maxCountCmb.SelectedIndex =
objCustomization.CustomSettings
.Where(p => p.CustomizationType == selCustomizationType && p.CategoryID == selCategoryID)
.Select(p => p.DefaultFreeCount)
.DefaultIfEmpty(-1)
.First();
Sure you can:
var item = objCustomization.CustomSettings.FirstOrDefault(p => p.CustomizationType == selCustomizationType && p.CategoryID == selCategoryID);
chkFixLimit.Checked = item != null && item.IsDefaultLimit;
Or single statement, as you wish:
chkFixLimit.Checked = new Func<bool>(() => {
var item = objCustomization.CustomSettings.FirstOrDefault(p => p.CustomizationType == selCustomizationType && p.CategoryID == selCategoryID);
return item != null && item.IsDefaultLimit;
}).Invoke();
chkFixLimit.Checked = objCustomization.CustomSettings
.Where(p => p.CustomizationType == selCustomizationType
&& p.CategoryID == selCategoryID)
.Select(c => c.IsDefaultLimit)
.FirstOrDefault();
This not in one line but it is more readable, you can change:
var setting = objCustomization.CustomSettings
.FirstOrDefault(p => p.CustomizationType == selCustomizationType
&& p.CategoryID == selCategoryID);
chkFixLimit.Checked = setting == null ? false : setting.IsDefaultLimit;
That code is more-or-less the use case of the FirstOrDefault method. If something exists, return the first such item, and return a default value (null for reference types) if it doesn't. So you could just do:
var item = objCustomization.CustomSettings.FirstOrDefault
(p => p.CustomizationType == selCustomizationType && p.CategoryID)
and as result, the item object will either be null (assuming you indeed work with a reference type), or it will have a value.
After that you can just check that, with a simple
chkFixLimit.Checked = (item == null) ? false : item.IsDefaultLimit;

Categories