LINQ combine select and update query - c#

I have a LINQ database operation that looks like this:
using (SomeDC TheDC = new SomeDC())
{
var SomeData = (from .... select x).ToList();
if (SomeData.Count() > 0)
{
foreach (.... in SomeData) { x.SomeProp = NewProp; }
TheDC.SubmitChanges();
}
}
As you can see, I'm reading a list, then I'm updating this list, and finally I'm writing it back to the DB. Is there a way to combine this operation in just one query?

Is there a way to combine this operation in just one query?
Not in Linq - you could execute one SQL statement directly if there's a pattern to the updates, but querying and updating are two separate methods.

No, you should keep using a simple loop to manipulate your objects.There is no method for updating in LINQ.As the name suggests: Language Integrated Query, LINQ used for querying not for updating.
You could manually generate the sql query for your update operation then execute it via SqlQuery method or you can also execute Stored Procedures with Entity Framework if you wish.

There isn't really a single update select statement, however you could shorten your code and drop the ToList() call.
Additionally the check of count is unnecessary as the foreach wouldn't operate for an empty loop anyhow.
using (SomeDC TheDC = new SomeDC())
{
var SomeData = (from .... select x);
foreach (.... in SomeData) { x.SomeProp = NewProp; }
TheDC.SubmitChanges();
}
Alternatively if you are desperate to just do it in a single execute you can roll your own extension method to help.
public static class DatabaseHelper {
public static void Apply<T>(this IEnumerable<T> collection, Action<T> action) {
if (collection == null) { // Sanity check
return;
}
foreach (var item in collection) {
action(item);
}
}
}
Then your code would be
using (SomeDC TheDC = new SomeDC()) {
(from ... select x).Apply(x => x.SomeProp = NewProp);
TheDC.SubmitChanges();
}

Related

Mongodb AsQueryable() Performance

I have code like this where I want to query to MongoDB using Linq.
I get an AsQueryable from MongoDB collection.
public IEnumerable<IVideo> GetVideos()
{
var collection = database.GetCollection<IVideo>("Videos");
return collection.AsQueryable();
}
I call it like so,
var finalList = Filter2(Filter1(GetVideos())).Skip(2).Take(30);
foreach(var v in finalList)
{
....
}
Functions with the queries.
public IEnumerable<IVideo> Filter1(IEnumerable<IVideo> list)
{
return list.Where(q=>q.Categorized)
}
public IEnumerable<IVideo> Filter2(IEnumerable<IVideo> list)
{
var query = from d in list
where d.File == "string1" || d.File == "string2"
select d;
return query;
}
My code works fine. I have my code hosted in an IIS and have around 50,000 records and the queries are a bit complex than the example. My worker process spikes to 17% and takes a few seconds to execute when the foreach is called. This is a ridiculous high for such a low date amount.
I have a couple of questions.
Is the query being executed by .net or MongoDB? If it is executed by MongoDB why is my worker process taking such a hit?
What are the steps I can take to improve the execution time to render the query and reduce the server load.
Thanks
You're downloading all entries client-side by accident
public IEnumerable<IVideo> Filter1(IEnumerable<IVideo> list)
{
var list = list.Where(q=>q.Categorized)
}
IEnumerable causes the queryable to execute and return results. Change the filter methods to accept and return IQueryable.
EDIT:
The code you posted:
public IEnumerable<IVideo> Filter1(IEnumerable<IVideo> list)
{
var list = list.Where(q=>q.Categorized)
}
Does not compile.
Your code should look like this:
public IQueryable<IVideo> Filter1(IQueryable<IVideo> qVideos)
{
return qVideos.Where(q => q.Categorized);
}
public IQueryable<IVideo> Filter2(IQueryable<IVideo> qVideos)
{
return qVideos
.Where(e => e.File == "string1" || e.File == "string2");
}
public DoSomething()
{
// This is the query, in debug mode you can inspect the actual query generated under a property called 'DebugView'
var qVideos = Filter2(Filter1(GetVideos()))
.Skip(1)
.Take(30);
// This runs the actual query and loads the results client side.
var videos = qVideos.ToList();
// now iterated
foreach (var video in videos)
{
}
}

Generic query with Entity Framework ORM

So currently i am writing a specific SQL function to get a specific row from a specific table.
However, I have dozens of tables, and noticed that I am writing these same 'get row' repository functions each time I make a new table.
Is it possible to write a generic function that works for every table, in this case to get a specific row?
Current (Example)
public Purchase GetPurchase(long purchaseId)
{
using (var db = new DbContext(_connStringKey))
{
var result = (from p in db.Purchases
where p.PurchaseId.Equals(purchaseId)
select p).FirstOrDefault();
return result;
}
}
Generic Example (To give you an idea)
public Object GenericGet (string tableName, string rowName, long rowId)
{
using (var db = new DbContext(_connStringKey))
{
var result = (from p in db.tableName
where p.rowName.Equals(rowId)
select p).FirstOrDefault();
return result;
}
}
You can do it using reflection but it is not a good approach. Instead of this, you could try something using the generics aspects of the language, and make sure what you want, for sample:
public T Get<T>(Expression<Func<T, bool>> filter)
where T : class
{
T result;
using (var db = new DbContext(_connStringKey))
{
result = db.Set<T>().FirstOrDefault(filter);
}
return result;
}
Remember that the T must be a reference type, so, define a constraint for class
Then, you could try this:
var product = Get<Product>(p => p.Name == "Something");
var supplier = Get<Supplier>(p => p.Sector == "Manufacturing");

How to Call Method in LINQ Select

I have the following method:
internal void DuplicateGroup(int oldGroupId, int newGroupId) {
IEnumerable<int> res = (from p in Db.table
where p.GroupID == oldGroupId
select p.packSizeID);
foreach (int ps in res)
Db.table.Add(new entityclass { GroupID = newGroupId, packSizeID = ps });
}
The method builds a List from desired IDs then adds new rescords to the same table with newGroupIDs. The question is: is it possible to call method within select?
Not in that select no, but in some selects, yes. It depends on the data source. LINQ over EF, no, but LINQ over objects, yes.

Simple LINQ Query with LINQ to SQL, think I'm doing something wrong

I have a table in my LINQ to SQL portion of my project.
I'm just trying to perform a simple query like so:
public static string GetMLBID(int fk_players_id)
{
using (MLBDataClassesDataContext context = new MLBDataClassesDataContext())
{
var query = from a in context.players
where a.fk_player_type_id == fk_players_id
select a.mlb_com_id;
foreach (var b in query)
{
Console.WriteLine(b.); //<-- I don't get the properties listed in the "players" table that i linked in the imgur link.
}
}
}
From all the examples in google.. where i have "b.", the properties from the table i have should be popping up.. but that's not listed. i only get simple LINQ operators and methods.
I feel like i'm missing something really simple.. any help?
You are only selecting the id mlb_com_id
select a.mlb_com_id;
Change the select clause to
select a;
This allows you to access all the public members of a on the result set.
EDIT by Pellared. (The point of Pellared's addition is that the extension method syntax does not require a Select-clause and would therefore not have lead to the error):
You can also change the query using lamba expressions (which a lot of people prefer)
public static string GetMLBID(int fk_players_id)
{
using (MLBDataClassesDataContext context = new MLBDataClassesDataContext())
{
var query = context.players
.Where(a => a.fk_player_type_id == fk_players_id);
foreach (var b in query)
{
Console.WriteLine(b.mlb_com_id);
}
}
}
You need to get your elements as a list and you should be able to access the properties then.
public static string GetMLBID(int fk_players_id) {
using (MLBDataClassesDataContext context = new MLBDataClassesDataContext())
{
var query = (from a in context.players
where a.fk_player_type_id == fk_players_id
select a).ToList();
foreach (var b in query)
{
Console.WriteLine(b.first_name);
}
}
}

Update a List of entries using a List of ID's in EntityFramework

I'm using the following code to store a list of connectionID's in a List<string>:
List<string> connectionIds =
connectedUsers.Where(x => x.UserId == userId).Select(x => x.ConnectionId).ToList();
I need to update the Database to set the connection status to false when it finds the corresponding ID's. So far, I am using the following code:
if (connectionIds.Any())
{
foreach (string connectionId in connectionIds)
{
Connection curConn = db.Connection.FirstOrDefault(x => x.ConnectionID == connectionId);
if (curConn != null)
curConn.Connected = false;
db.SaveChanges();
}
}
However, this makes a call to the DB for each connection... Is there any simple way to update the connection in an easier process?
You can use the Contains method. This will result in a single query for loading the connection objects. Once you have the result of the query, loop through the results to update the Connected flag, and then save the changes.
List<string> connectionIds = ...;
if (connectionIds.Any()) {
var data = db.Connection
.Where(x => connectionIds.Contains(x.ConnectionID))
.ToList();
foreach (var item in data) {
item.Connected = false;
}
db.SaveChanges();
}
You want to perform batch updates in one SQL statement with EF. EF doesn't support this in a straightforward manner. See here for a possible solution.

Categories