I have lots of queries like sample1,sample2 and sample3. There are more than 13 million records in mongodb collection. So this query getting long time. Is there any way to faster this query?
I think using IMongoQuery object to resolve this problem. Is there any better way?
Sample 1:
var collection = new MongoDbRepo().DbCollection<Model>("tblmodel");
decimal total1 = collection.FindAll()
.SelectMany(x => x.MMB.MVD)
.Where(x => x.M01.ToLower() == "try")
.Sum(x => x.M06);
Sample 2:
var collection = new MongoDbRepo().DbCollection<Model>("tblmodel");
decimal total2 = collection.FindAll().Sum(x => x.MMB.MVO.O01);
Sample 3:
var list1= collection.FindAll()
.SelectMany(x => x.MHB.VLH)
.Where(x => x.V15 > 1).ToList();
var list2= list1.GroupBy(x => new { x.H03, x.H09 })
.Select(lg =>
new
{
Prop1= lg.Key.H03,
Prop2= lg.Count(),
Prop3= lg.Sum(w => w.H09),
});
The function FindAll returns a MongoCursor. When you add LINQ extension methods on to the FindAll, all of the processing happens on the client, not the Database server. Every document is returned to the client. Ideally, you'll need to pass in a query to limit the results by using Find.
Or, you could use the AsQueryable function to better utilize LINQ expressions and the extension methods:
var results = collection.AsQueryable().Where(....);
I don't understand your data model, so I can't offer any specific suggestions as to how to add a query that would filter more of the data on the server.
You can use the SetFields chainable method after FindAll to limit the fields that are returned if you really do need to return every document to the client for processing.
You also might find that writing some of the queries using the MongoDB aggregation framework might produce similar results, without sending any data to the client (except the results). Or, possibly a Map-Reduce depending on the nature of the data.
Related
I am trying to use LINQ methods to filte a list of client by cheking whether or not the client is in a table of my BDD
using(var db = new CrmXefi())
{
var activeAccount = db.AccountBase.Where(account => account.StateCode == 0);
List<Client> toImport = clients.Where(client => activeAccount
.Where(account => account.IsAccountSageNumberForAgency(client.CODECLIENT, new Guid("2CA81DBC-8261-EB11-B061-00155D53D276")))
.Any()).ToList();
}
LINQ cannot translate that expression. I've checked the type of my elements to make sure that none of the ones inside the queries are IEnumerable. Can't find the origin of the problem.
This expression works :
var test = activeAccount.Where(account => account.IsAccountSageNumberForAgency("", new Guid("2CA81DBC-8261-EB11-B061-00155D53D276")));
is it because I get client.CODECLIENT in a Where() that is inside an other Where() and client is the in the first predicate?
Your query cannot be executed on the database side, so you will have to do it client side, by loading all the objects in memory.
You can use ToList() to achieve this.
By example :
using(var db = new CrmXefi())
{
var activeAccount = db.AccountBase.Where(account => account.StateCode == 0);
List<Client> toImport = clients.ToList().Where(client => activeAccount
.Where(account => account.IsAccountSageNumberForAgency(client.CODECLIENT, new Guid("2CA81DBC-8261-EB11-B061-00155D53D276")))
.Any()).ToList();
}
"Linq" is confusing here. On one side you have the "traditional" Linq, that works on IEnumerable and does all the processing in memory. On the other side you have Frameworks like Entity Framework that uses a Linq-like interface to compose queries. Ef Core is actually based on "Linq2Sql". EF converts your Linq to SQL and sends that to the server (it works on the IQueryable type. But not everything can be converted to SQL. In your case you're calling a specific method of a class, which is specific to your C# code. The SQL server doesn't know anything about it. And EF cannot convert it an expression.
Unless you can make something that can run on the server, you will need to pull the data to the local memory. You can do that with AsEnumerable.
E.g.
List<Client> toImport = clients
.AsEnumerable()
.Where(client => activeAccount
.Where(account => account
.IsAccountSageNumberForAgency(
client.CODECLIENT,
new Guid("2CA81DBC-8261-EB11-B061-00155D53D276")))
.Any())
.ToList();
Note, this will pull all data from the server to the local memory, thus costs memory and performance
I am having difficulty understanding how Entity Framework generates a single SQL Query from a couple of Linq methods. Here is a code which selects Username from a table.
var result1 = context.UserMasters
.Where(t => t.UserRole == "LOCAL")
.Skip(100)
.Take(100)
.Select(t => new { t.UserName });
Typically the above code is identical to the below code.
var test = context.UserMasters.Where(t=> t.UserRole == "LOCAL");
test = test.Skip(100);
test = test.Take(100);
var result2 = test.Select(t => new { t.UserName });
I hope we can get results from the table after any Linq Method. So there is a list readily available always. Is it selecting all results from the table initially and doing operation on the list ?
If the type is IQueryable, then the filtering of data happens at the database side. But if the type of query is IEnumerable or other than IQueryable, all the data from the table is fetched and filtering is done at .Net side. It is always advised to use IQueryable in these cases. Please read about IQueryable and IEnumerable difference.
I have a problem where the we have a lot of data grouped into what are called stages. The front end wants to display this data, grouped in stages, before rendering it. The number of stages is variable. So originally they were making an api per stage to bunching up the data before binding to a grid control.
When the number of stages become quite high, it becomes too slow. The browser will queue api requests and the overall response time would be very long. Better - we decided - would be to have a single api call that can deal with grouping AND paging. That is, you could say 'take=30' and it would give you 30 records of EACH stage, for however many stages there are.
So the query on the back end looks like what I have below. The problems is that the sorting of the data, before the skip and take is on a dynamic field, and this is where it falls over. Dynamic Linq doesn't seem to work (although it works perfectly fine for normal queries outside the GroupBy call), and I haven't been able to get any of the huge number of extension methods out there working either. They are all some variation of the errors you would find below: (Keep in mind the problem is getting it working with linq to sql)
TestEntities context = new TestEntities();
List<TestTable1> result;
// This works (Hard coding at design time)
result = context.TestTable1.GroupBy(x => x.StageId)
.SelectMany(x => x.OrderBy(y => y.StageId).Skip(1).Take(1)).ToList();
// This works (using a hard coded function at design time)
Func<TestTable1, int> orderByExpression = x => x.StageId;
result = context.TestTable1.GroupBy(x => x.StageId)
.SelectMany(x => x.OrderBy(orderByExpression).Skip(1).Take(1)).ToList();
// This doesn't work. Dynamic linq
result = context.TestTable1.GroupBy(x => x.StageId)
.SelectMany(x => x.AsQueryable().OrderBy("Name").Skip(1).Take(1)).ToList();
// This doesn't work. Can't convert an object to a primitive type
Func<TestTable1, object> orderByObjectExpression = x => x.StageId;
result = context.TestTable1.GroupBy(x => x.StageId)
.SelectMany(x => x.AsQueryable().OrderBy(orderByObjectExpression).Skip(1).Take(1)).ToList();
// This doesn't work. Same as above
Func<TestTable1, dynamic> orderByDynamicExpression = x => x.StageId;
result = context.TestTable1.GroupBy(x => x.StageId)
.SelectMany(x => x.AsQueryable().OrderBy(orderByObjectExpression).Skip(1).Take(1)).ToList();
Console.WriteLine(JsonConvert.SerializeObject(result));
Console.ReadKey();
I have a simple scenario.I want to list out all the employees except the logged in user.
Similar SQL Condition is
select * from employee where id not in(_loggedUserId)
How can I acheive the above using LINQ.I have tried the following query but not getting the desired list
int _loggedUserId = Convert.ToInt32(Session["LoggedUserId"]);
List<int> _empIds = _cmn.GetEmployeeCenterWise(_loggedUserId)
.Select(e => e.Id)
.Except(_loggedUserId)
.ToList();
Except expects argument of type IEnumerable<T>, not T, so it should be something like
_empIds = _cmn.GetEmployeeCenterWise(_loggedUserId)
.Select(e => e.Id)
.Except(new[] {_loggedUserId})
.ToList();
Also note, this is really redundant in the case when exclusion list contains only one item and can be replaces with something like .Where(x => x != _loggedUserId)
Why not use a very simple Where condition?
_empIds = _cmn.GetEmployeeCenterWise(_loggedUserId).Where(e=>e.Id != _loggedUserId).ToList();
The title of your question is how to perform a not in query against a database using LINQ. However, as others have pointed out your specific problem is better solved by a using users.Where(user => user.Id != loggedInUserId).
But there is still an answer on how to perform a query against a database using LINQ that results in NOT IN SQL being generated:
var userIdsToFilter = new[] { ... };
var filteredUsers = users.Where(user => !userIdsToFilter.Contains(user.Id));
That should generate the desired SQL using either Entity Framework or LINQ to SQL.
Entity Framework also allows you to use Except but then you will have to project the sequence to ID's before filtering them and if you need to original rows you need to fetch them again from the filtered sequence of ID's. So my advice is use Where with a Contains in the predicate.
Use LINQ without filtering. This will make your query execute much faster:
List<int> _empIds = _cmn.GetEmployeeCenterWise(_loggedUserId)
.Select(e => e.Id).ToList();
Now use List.Remove() to remove the logged-in user.
_empIds.Remove(_loggedUserId);
I have got a bit of an issue and was wondering if there is a way to have my cake and eat it.
Currently I have a Repository and Query style pattern for how I am using Linq2Sql, however I have got one issue and I cannot see a nice way to solve it. Here is an example of the problem:
var someDataMapper = new SomeDataMapper();
var someDataQuery = new GetSomeDataQuery();
var results = SomeRepository.HybridQuery(someDataQuery)
.Where(x => x.SomeColumn == 1 || x.SomeColumn == 2)
.OrderByDescending(x => x.SomeOtherColumn)
.Select(x => someDataMapper.Map(x));
return results.Where(x => x.SomeMappedColumn == "SomeType");
The main bits to pay attention to here are Mapper, Query, Repository and then the final where clause. I am doing this as part of a larger refactor, and we found that there were ALOT of similar queries which were getting slightly different result sets back but then mapping them the same way to a domain specific model. So take for example getting back a tbl_car and then mapping it to a Car object. So a mapper basically takes one type and spits out another, so exactly the same as what would normally happen in the select:
// Non mapped version
select(x => new Car
{
Id = x.Id,
Name = x.Name,
Owner = x.FirstName + x.Surname
});
// Mapped version
select(x => carMapper.Map(x));
So the car mapper is more re-usable on all areas which do similar queries returning same end results but doing different bits along the way. However I keep getting the error saying that Map is not able to be converted to SQL, which is fine as I dont want it to be, however I understand that as it is in an expression tree it would try to convert it.
{"Method 'SomeData Map(SomeTable)' has no supported translation to SQL."}
Finally the object that is returned and mapped is passed further up the stack for other objects to use, which make use of Linq to SQL's composition abilities to add additional criteria to the query then finally ToList() or itterate on the data returned, however they filter based on the mapped model, not the original table model, which I believe is perfectly fine as answered in a previous question:
Linq2Sql point of retrieving data
So to sum it up, can I use my mapping pattern as shown without it trying to convert that single part to SQL?
Yes, you can. Put AsEnumerable() before the last Select:
var results = SomeRepository.HybridQuery(someDataQuery)
.Where(x => x.SomeColumn == 1 || x.SomeColumn == 2)
.OrderByDescending(x => x.SomeOtherColumn)
.AsEnumerable()
.Select(x => someDataMapper.Map(x));
Please note, however, that the second Where - the one that operates on SomeMappedColumn - will now be executed in memory and not by the database. If this last where clause significantly reduces the result set this could be a problem.
An alternate approach would be to create a method that returns the expression tree of that mapping. Something like the following should work, as long as everything happening in the mapping is convertible to SQL.
Expression<Func<EntityType, Car>> GetCarMappingExpression()
{
return new Expression<Func<EntityType, Car>>(x => new Car
{
Id = x.Id,
Name = x.Name,
Owner = x.FirstName + x.Surname
});
}
Usage would be like this:
var results = SomeRepository.HybridQuery(someDataQuery)
.Where(x => x.SomeColumn == 1 || x.SomeColumn == 2)
.OrderByDescending(x => x.SomeOtherColumn)
.Select(GetCarMappingExpression());