Linq Multiple Expression - sql

I use ASP.NET and EF5. I need multiple condition with Linq. I need like this sql statement.
SELECT * FROM Products
WHERE (ProdName LIKE '%value1%' AND ProdName LIKE '%value2%' AND ProdName LIKE '%value3%')
OR (Keywords LIKE '%value4%')
How can i convert to linq the above sql. I've write this but it's not enough.
var prodQuery = from p in _db.Products
select new SearchResult
{
Product = p,
SearchResultType = SearchResultType.Prod
};
//this foreach has to be in brackets in sql
foreach (var s in searchText.Split(' '))
{
var temp = s;
prodQuery = prodQuery.Where(x => x.Product.ProdName.Contains(temp));
}
//and this foreach has to be in another bracket in sql and it has to connect with or clause
prodQuery = prodQuery.Where(x => x.Product.Keywords.Contains(searchText));

Try this:
var keywords = searchText.Split(' ');
var results = _db.Products.Where(p => keywords.Any(kw => kw.Contains(p.ProdName))
|| p.Keywords.Contains(searchText))
.Select(x => new SearchResult()
{
Product = x,
SearchResultType = SearchResultType.Prod
});

Related

How to query CosmosDb for multiple results using SqlQuerySpec

I'm trying to get multiple documents using a list of numbers. Here's my query
var queryString = "Select * from c Where c.id in (#list)";
var queryParam = new Microsoft.Azure.Documents.SqlParameter("#list", string.Join(",", list.Select(x => $"{x.Id}").ToArray()));
var result = repo.Query(
new SqlQuerySpec()
{
QueryText = queryString,
Parameters = new Microsoft.Azure.Documents.SqlParameterCollection()
{
queryParam
}
}
);
My Query function:
public IQueryable<TClass> Query(SqlQuerySpec sqlQuerySpec = null, bool allowScan = false, int? maxItems = null)
{
var feedOptions = new FeedOptions
{
EnableScanInQuery = allowScan,
MaxItemCount = maxItems,
EnableCrossPartitionQuery = true
};
var querySpec = sqlQuerySpec ?? new SqlQuerySpec();
return sqlQuerySpec != null
? Client.CreateDocumentQuery<TClass>(Collection.DocumentsLink, querySpec, feedOptions)
: Client.CreateDocumentQuery<TClass>(Collection.DocumentsLink, feedOptions);
}
It says there was an error: one of the specified inputs is invalid.
What am I doing wrong?
The id is a string so you would need to wrap each id with single quotes.
This line:
var queryParam = new Microsoft.Azure.Documents.SqlParameter("#list", string.Join(",", list.Select(x => $"{x.Id}").ToArray()));
Should be:
var queryParam = new Microsoft.Azure.Documents.SqlParameter("#list", string.Join(",", list.Select(x => $"'{x.Id}'").ToArray()));

Entity Framework Union And Paging

I am getting the result query by running two queries and joining them with union clause. I have to use paging but I need results as inserted line. I don't want to order it again. But when I use paging I have to use order by clause. how can I get results with natural order.
var prodFullTextQuery = _db.Products
.Where(x => !x.IsDeleted
&& x.ProdStatusValue == (int)ProdStatus.Active
&& (x.ProdName.Contains(searchText)
|| x.Keywords.Contains(searchText)
|| x.ManufacturerCode.StartsWith(searchText)
));
IQueryable<Product> prodQuery;
prodQuery = _db.Products.Where(x => !x.IsDeleted
&& x.ProdStatusValue == (int)ProdStatus.Active
&& x.VariantMainProdId == x.ProdId);
foreach (var s in searchText.Split(' '))
{
var temp = s;
prodQuery = prodQuery.Where(x => x.Keywords.Contains(temp));
}
prodFullTextQuery = prodFullTextQuery.Union(prodQuery)
//i need here by the order in which rows are inserted
var results= prodFullTextQuery
.OrderBy(x=>x.OrderId) //i don't want this
.Skip(prodCountPerPage * pageNumber)
.Take(prodCountPerPage)
.ToList()

Remove items from a collection in entity framework

I have a function as below :
IEnumerable<Group> GetAllChildren(int parentID)
{
using (Entities db = new Entities())
{
var result = (from x in db.Groups
where x.ParentID == parentID
select x).ToList();
foreach (Group child in result.ToList())
{
result.AddRange(GetAllChildren(child.GroupID));
}
return result;
}
}
In the above function if I pass a group name I get all the children at all levels.
It works as expected.
Now my query looks like something like :
GroupNamesWithCorrespondingEffects
= new ObservableCollection<GroupNameWithCorrespondingEffect>
(from g in db.Groups
select new GroupNameWithCorrespondingEffect
{
GroupID = g.GroupID,
GroupName = g.GroupName,
CorrespondingEffect = g.Master_Effects.Effect
}
);
The above query will give me all the groups.
Now I want to remove all the groups from GroupNamesWithCorrespondingEffects that are children of a group with id == 25.
I have tried .Remove(GetAllChildren(25)) in 2nd query. but I get following error.
Collection.Remove(GroupNameWithCorrespondingEffect) has some invalid arguments.
hope this help you:
var childs = GetAllChildren(25).ToList();
var childIDList = childs.select(u => u.GroupID).ToList();
GroupNamesWithCorrespondingEffects = GroupNamesWithCorrespondingEffects
.Where(u => !childIDList.Contains(u.GroupID)).ToList();

dynamically change LINQ to Entity query

int year = 2009; // get summ of TONS2009 column
var query = from ODInfo in DataContext.CIMS_TRUCKS
where pLocationIDs.Contains(ODInfo.OID)
group ODInfo by ODInfo.OID into g
select new
{
OID = g.Key,
TotalTons = g.Sum( ODInfo => ODInfo.TONS2009)
};
IN the expression 'ODInfo => ODInfo.TONS2009', how do I change TONS2009 to TONS2010 or TONS2011 based on the method parameter 'int year' ?
K06a's answer is close but won't work server-side. Try this:
IEnumerable<OutputType> myQuery(IEnumerable<InputType> data, Expression<Func<InputType,decimal>> expr)
{
return from ODInfo in DataContext.CIMS_TRUCKS
where pLocationIDs.Contains(ODInfo.OID)
group ODInfo by ODInfo.OID into g
select new OutputType
{
OID = g.Key,
TotalTons = g.AsQueryable().Sum(expr)
};
}
var query = myQuery(DataContext.CIMS_TRUCKS, ODInfo => ODInfo.TONS2009);
I haven't tried this, but did something similar here.
UPDATE
If you really need to translate input strings (like "2009") to expressions, it's still possible:
string year = "2009";
Type ODInfoType = typeof(ODINFOTYPE); // substitute with the type of ODInfo
ParameterExpression pe = ParameterExpression.Parameter(ODInfoType, "ODInfo");
MemberInfo mi = ODInfoType.GetProperty("TONS" + year);
MemberExpression me = Expression.MakeMemberAccess(pe, mi);
var expr = Expression.Lambda<Func<ODINFOTYPE, decimal>>(me, pe);
Be aware that this is a patch to the extremly evil structure of your database.
You can try something like that:
TotalTons = g.Sum( ODInfo => (year == 2009) ? ODInfo.TONS2009 : ((year == 2010)
? ODInfo.TONS2010 : ODInfo.TONS2011))
Or make it more readable and use { } to split that lambda expression into more then one line and use eg. switch statement.
The best solution is to break this up into multiple querys that you can compose to a final query:
int year = 2009; // get summ of TONS2009 column
var odInfos =
year == 2009 ? DataContext.CIMS_TRUCKS.Select(x => new { x.OID, TONS = x.TONS2009 })
year == 2010 ? DataContext.CIMS_TRUCKS.Select(x => new { x.OID, TONS = x.TONS2010 })
year == 2011 ? DataContext.CIMS_TRUCKS.Select(x => new { x.OID, TONS = x.TONS2011 })
: null;
var query = from ODInfo in odInfos
where pLocationIDs.Contains(ODInfo.OID)
group ODInfo by ODInfo.OID into g
select new
{
OID = g.Key,
TotalTons = g.Sum(ODInfo => ODInfo.TONS)
};
This will specialize to three possible queries at runtime, thereby giving the best possible performance. It is better than a case-switch.
Try this way:
IEnumerable<OutputType> myQuery(IEnumerable<InputType> data, Func<InputType,decimal> func)
{
return from ODInfo in data
where pLocationIDs.Contains(ODInfo.OID)
group ODInfo by ODInfo.OID into g
select new OutputType
{
OID = g.Key,
TotalTons = g.Sum(func)
};
}
var query = myQuery(DataContext.CIMS_TRUCKS, ODInfo => ODInfo.TONS2009);
Using DynamicLinq which works with EF also:
int year = 2009; // get summ of TONS2009 column
var query = from ODInfo in DataContext.CIMS_TRUCKS
where pLocationIDs.Contains(ODInfo.OID)
group ODInfo by ODInfo.OID into g
select g;
var projectedGroups = query.Select("new (Key as OID, Sum(TONS" + year + ") as TotalTons)");

How do I append Skip and Take to an nHibernate IQueryOver

I want to do this:
NHibernate.IQueryOver<DataAccess.Domain.Product, DataAccess.Domain.Product> query = session.QueryOver<DataAccess.Domain.Product>();
query = query.Where(x => x.Name == "X");
query = query.Take(1).Skip(3);
List<Product> results = query.List().ToList();
I cant find any help on Skip or Take. The tooltip help (yes I'm that desperate) says that Skip and Take return IQueryOver but the error message says something to the effect "Cant implicitly convert IQueryOver{T} to IQueryOver{T,T}. I don't know what IQueryOver{T,T} is. I didn't ask for one of those anyway.
Try to change your code like this:
NHibernate.IQueryOver<DataAccess.Domain.Product> query = session.QueryOver<DataAccess.Domain.Product>();
query = query.Where(x => x.Name == "X");
query = query.Take(1).Skip(3);
var results = query.List();
Or, even better:
var results = session.QueryOver<DataAccess.Domain.Product>()
.Where(x => x.Name == "X")
.Take(1)
.Skip(3)
.List();
You can check my code here downloading NHibernateQueryOver.
UPDATE:
I think you're missing something. I would suggest you to read this article which has been really helpful for me.
In the paragraph about Associations they say:
An IQueryOver has two types of interest; the root type (the type of entity that the query returns), and the type of the 'current' entity
being queried. For example, the following query uses a join to create
a sub-QueryOver (analagous to creating sub-criteria in the ICriteria
API):
IQueryOver<Cat,Kitten> catQuery =
session.QueryOver<Cat>()
.JoinQueryOver(c => c.Kittens)
.Where(k => k.Name == "Tiddles");
The JoinQueryOver returns a new instance of the IQueryOver than has
its root at the Kittens collection. The default type for restrictions
is now Kitten (restricting on the name 'Tiddles' in the above
example), while calling .List() will return an IList. The type
IQueryOver inherits from IQueryOver.
This is what I do when I want to build multiple filter:
Domain.OrderAddress addressDestination = null;
Domain.Customer customer = null;
Domain.TermsConditionsOfSale termsConditionsOfSale = null;
ICriterion filter1 = Restrictions.Where<Domain.Order>(t => t.Company == "MYCOMPANY");
ICriterion filter2 = Restrictions.Where<Domain.Order>(t => t.WareHouseDelivery == "DEPXX");
ICriterion filter3 = Restrictions.Where<Domain.Order>(t => t.Status == "X");
ICriterion filter4 = Restrictions.Where(() => addressDestination.AddressType == "99");
ICriterion filter5 = Restrictions.Where(() => addressDestination.Province.IsIn(new string[] { "AA", "BB", "CC" }));
ICriterion filter6 = Restrictions.Where(() => termsConditionsOfSale.ReturnedGoodsCode != "01");
var ordersForProvinces = session.QueryOver<Domain.Order>()
.Inner.JoinAlias(t => t.OrderAddresses, () => addressDestination)
.Inner.JoinAlias(t => t.Customer, () => customer)
.Left.JoinAlias(t => t.TermsConditionsOfSale, () => termsConditionsOfSale);
ordersForProvinces
.Where(filter1)
.And(filter2)
.And(filter3)
.And(filter4)
.And(filter5)
.And(filter6);
var Results = ordersForProvinces.Skip(50).Take(20).List();
UPDATE-UPDATE:
NHibernate.IQueryOver<Domain.Person> person = session.QueryOver<Domain.Person>();
var myList = DoSomething(person);
Method:
private static IList<Domain.Person> DoSomething(NHibernate.IQueryOver<Domain.Person> persons)
{
ICriterion filter1 = Restrictions.Where<Domain.Person>(t => t.CompanyName.IsLike("Customer%"));
persons.RootCriteria.Add(filter1);
var x = persons.Skip(1).Take(3).List();
return (x);
}