Replacing foreach loops with LINQ expressions - linq

replacing the foreach loop
IList<EmployeeSearch> empItems = new List<EmployeeSearch>();
EmployeeSearch empItem = new EmployeeSearch();
foreach (var _emp in mediaResults.results)
{
empItem.Title = _emp.title;
empItem.Desc = _emp.description;
empItems.Add(empItem);
}
with the following linq expression and getting error:
empItems = from _emp in employeeResults.results
select new EmployeeSearch
{
Title = _emp.title,
Desc = _emp.description
};
Error:
Error 2 Cannot implicitly convert type 'System.Collections.Generic.IEnumerable' to 'System.Collections.Generic.IList'. An explicit conversion exists (are you

You need to convert it to a List:
(from _emp in employeeResults.results
select new EmployeeSearch
{
Title = _emp.title,
Desc = _emp.description
}).ToList();
Or...change your empItems definitions to use a var implicit typing:
var empItems = from _emp in employeeResults.results
select new EmployeeSearch
{
Title = _emp.title,
Desc = _emp.description
};
empItems will be an IEnumerable of EmployeeSearch objects.

Either add a call to the ToList extension method at the end of your query:
empItems =
(from _emp in employeeResults.results
select new EmployeeSearch
{
Title = _emp.title,
Desc = _emp.description
})
.ToList();
Or if you can possibly refactor your code to use an IEnumerable<T> instead, that could possibly be better:
IEnumerable<EmployeeSearch> empItems =
from _emp in employeeResults.results
select new EmployeeSearch
{
Title = _emp.title,
Desc = _emp.description
};
This should generally be used if you're just looping through the results and you don't actually need to add / remove elements from the result set or have per-index access to the results. Converting the query results to a list requires allocation of a single, contiguous array in memory, which is a fairly expensive operation.

Related

IQueryable.Union/Concat in .net core 3

I want to add a dummy member to an IQueryable and came up with this solution:
IQueryable<Geography> geographies = _unitOfWork.GeographyRepository.GetAll(); //DbSet<Geography>
var dummyGeographies = new Geography[] { new Geography { Id = -1, Name = "All" } }.AsQueryable();
var combinedGeographies = geographies.Union(dummyGeographies);
var test = combinedGeographies.ToList(); //throws runtime exc
But it throws the following exception:
Processing of the LINQ expression 'DbSet
.Union(EnumerableQuery { Geography, })' by 'NavigationExpandingExpressionVisitor' failed. This may indicate either a bug or a limitation in EF Core.
How could I make it work?!
you can only union on data structure which are the same
IQueryable is only applicable if the query expression not been been expressed (ToList) before its run against db and you want the expression modifiable . aka nothing which which is not going to db as a query needs to be IQueryable (simple explanation better to research and understand this yourself)
List<Geography> geographies = _unitOfWork.GeographyRepository
.GetAll() //DbSet<Geography>
.Select(o => new Geography { Id = o.Id, Name = o.Name })
.ToList();
List<Geography> dummyGeographies = new List<Geography>() {
new Geography[] { new Geography { Id = -1, Name = "All" } }
};
var combinedGeographies = geographies.Union(dummyGeographies);
var test = combinedGeographies.ToList();
I was able to achieve it with the following code:
IQueryable<Geography> geographies = _unitOfWork.GeographyRepository.GetAll().Select(o => new Geography { Id = o.Id, Name = o.Name });
IQueryable<Geography> dummyGeographies = _unitOfWork.GeographyRepository.GetAll().Select(o => new Geography { Id = -1, Name = "All" });
var combinedGeographies = geographies.Union(dummyGeographies);

Load multipe sharepoint list item fields in one Go using CSOM c#

***ctx.Load(listItemCollection,
eachItem => eachItem.Include(
item => item,
item => item["Column1"],
item => item["Column2"]
));***
i have list of fields in a array of string instead of column1 and column2, how can i pass it through in include linq, not able to create proper lambda on runtime. i tried following ways but couldn't get success. Static befor loops works but thw fields added in loop fails as it doesn't evaluate string value in loop
***Expression<Func<ListItem, object>>[] paramss = new
Expression<Func<ListItem, object>>[length];
paramss[0] = x => x.ContentType;
paramss[1] = x => x["Title"];
count = 2;
foreach (string item in solConnDefModel.Columns)
{ paramss[count] = x => x[item];
count++;
}***
Please take a reference of below code:
List dlist = context.Web.Lists.GetByTitle("listname");
context.Load(dlist);
context.ExecuteQuery();
string[] fieldNames = { "Id", "Title", "num", "mStartDate" };
// Create the expression used to define the fields to be included
List<Expression<Func<ListItemCollection, object>>> fieldsToBeIncluded = new List<Expression<Func<ListItemCollection, object>>>();
foreach (string s in fieldNames)
{
fieldsToBeIncluded.Add(items => items.Include(item => item[s]));
}
// Initialize the collection of list items
var listItems = dlist.GetItems(new CamlQuery());
context.Load(listItems, fieldsToBeIncluded.ToArray());
context.ExecuteQuery();
You can hover on load method to see what type parameter it requires, then generate a corresponding one and pass it.
i have to create lambda expression at runtime. following code i was able to get expected value
Expression<Func<ListItem, object>>[] paramss = new Expression<Func<ListItem, object>>[length];
foreach (string item in Columns)
{
if (item.ToLower() != "contenttype")
{
ParameterExpression parameter = Expression.Parameter(typeof(ListItem), "x");
var propertyInfo = typeof(ListItem).GetMethod("get_Item");
var arguments = new List<Expression> { Expression.Constant(item) };
var expression = Expression.Call(parameter, propertyInfo, arguments);
var lambda = Expression.Lambda<Func<ListItem, object>>(expression, parameter);
paramss[count] = lambda;
}
else
{
paramss[count] = x => x.ContentType;
}
count++;
}

EF Core LINQ use scalar function

I use Entity Framework Core 2.1.
I have a scalar function in the database which adds specified number of days.
I created an extension method to execute it:
public static class AdventureWorks2012ContextExt
{
public static DateTime? ExecFn_AddDayPeriod(this AdventureWorks2012Context db, DateTime dateTime, int days, string periodName)
{
var sql = $"set #result = dbo.[fn_AddDayPeriod]('{dateTime.ToString("yyyy-MM-dd HH:mm:ss.fff")}', {days}, '{periodName}')";
var output = new SqlParameter { ParameterName = #"result", DbType = DbType.DateTime, Size = 16, Direction = ParameterDirection.Output };
var result = db.Database.ExecuteSqlCommand(sql, output);
return output.Value as DateTime?;
}
}
I try to use a scalar function in the query (to simplify things I use AdventureWorks2012) as follows:
var persons =
(from p in db.Person
join pa in db.Address on p.BusinessEntityId equals pa.AddressId
where p.ModifiedDate > db.ExecFn_AddDayPeriod(pa.ModifiedDate, 100, "DayPeriod_day")
select p).ToList();
But get an System.InvalidOperationException: 'A second operation started on this context before a previous operation completed. Any instance members are not guaranteed to be thread safe.'
How can I achieve this?
UPDATE:
I managed to do it with the help of Ivan's answer:
var persons =
(from p in db.Person
join bea in db.BusinessEntityAddress on p.BusinessEntityId equals bea.BusinessEntityId
join a in db.Address on bea.AddressId equals a.AddressId
where p.ModifiedDate > AdventureWorks2012ContextFunctions.AddDayPeriod(a.ModifiedDate, 100, "DayPeriod_day")
select p).ToList();
But now I need to update ModifiedDate for filtered persons. So I'm doing like this:
var persons =
(from p in db.Person
join bea in db.BusinessEntityAddress on p.BusinessEntityId equals bea.BusinessEntityId
join a in db.Address on bea.AddressId equals a.AddressId
let date = AdventureWorks2012ContextFunctions.AddDayPeriod(a.ModifiedDate, 100, "DayPeriod_day")
where p.ModifiedDate > date
select new { Person = p, NewDate = date }).ToList();
foreach (var p in persons)
p.Person.ModifiedDate = p.NewDate ?? DateTime.Now;
db.SaveChanges();
But got System.NotSupportedException: 'Specified method is not supported.'
How can I use scalar function in select statement?
I tried to split the query by two parts:
var filteredPersons = // ok
(from p in db.Person
join bea in db.BusinessEntityAddress on p.BusinessEntityId equals bea.BusinessEntityId
join a in db.Address on bea.AddressId equals a.AddressId
where p.ModifiedDate > AdventureWorks2012ContextFunctions.AddDayPeriod(a.ModifiedDate, 100, "DayPeriod_day")
select new { Person = p, a.ModifiedDate }).ToList();
var persons = // here an exception occurs
(from p in filteredPersons
select new { Person = p, NewDate = AdventureWorks2012ContextFunctions.AddDayPeriod(p.ModifiedDate, 100, "DayPeriod_day") }).ToList();
Instead of invoking the function client side (which is this particular case happens as part of the client evaluation of the query filter, while the query reading is still in progress), you can use EF Core Database scalar function mapping so it
can be used in LINQ queries and translated to SQL.
One way to do that is to create a public static method in the derived context class and mark it with DbFunction attribute:
public partial class AdventureWorks2012Context
{
[DbFunction("fn_AddDayPeriod")]
public static DateTime? AddDayPeriod(DateTime dateTime, int days, string periodName) => throw new NotSupportedException();
}
and use
where p.ModifiedDate > AdventureWorks2012Context.AddDayPeriod(pa.ModifiedDate, 100, "DayPeriod_day")
Another way is to create a public static method in another class
public static class AdventureWorks2012DbFunctions
{
[DbFunction("fn_AddDayPeriod")]
public static DateTime? AddDayPeriod(DateTime dateTime, int days, string periodName) => throw new NotSupportedException();
}
but then you'll need to register it with fluent API (which happens automatically for methods defined inside the context derived class):
modelBuilder
.HasDbFunction(() => AdventureWorks2012DbFunctions.AddDayPeriod(default(DateTime), default(int), default(string)));
The usage is the same:
where p.ModifiedDate > AdventureWorksDbFunctions.AddDayPeriod(pa.ModifiedDate, 100, "DayPeriod_day")

Add dynamic property to Linq result set objects

I have object lists:
List<dynamic> prods = new List<dynamic>();
foreach (DataRow row in dataTable.Rows)
{
dynamic obj = new ExpandoObject();
IDictionary<string, object> oprops = obj;
foreach (System.Data.DataColumn col in dataTable.Columns)
oprops.Add(col.ColumnName, row[col.ColumnName]);
obj = oprops;
list.Add(obj);
}
And pricing list is filled the same way from the DataTable having product pricing.
I have this query:
var result = (from product in prods join price in pricing on product.ID equals price.ProductID select new { product, price }).ToList();
And I want to add some more properties to the result set.
foreach (dynamic obj in q)
{
obj.Test = "yes, testing."; // This line gives runtime error
Console.WriteLine(
"{0} - {1}",
obj.product.Name,
obj.price.UnitPrice);
}
I have some more objects/values to add to the each individual result object in foreach loop.
I am just unable to do that as it throws runtime error as follows:
<>f__AnonymousType1<dynamic,dynamic>' does not contain a definition for 'Test' and no extension method 'Test' accepting a first argument of type '<>f__AnonymousType1<dynamic,dynamic>' could be found (are you missing a using directive or an assembly reference?)
Add the property while querying the data so it is there to set in the foreach loop; eg:
var result = (from product in prods
join price in pricing on product.ID equals price.ProductID
select new { product, price, Test = (string)null, }
).ToList();
or, something I've never tried, maybe use an ExpandoObject:
var result = (from product in prods
join price in pricing on product.ID equals price.ProductID
select new ExpandoObject { product, price }
).ToList();
So, this is what I have found, we cant expand the linq query result set however creating a new exapndo objects solves the problem which enables adding new properties.
This is actually what I did:
List<dynamic> list = new List<dynamic>();
foreach (var o in q)
{
dynamic obj = new ExpandoObject();
IDictionary<string, object> oprops = obj;
oprops.Add("Test", "yes, testing!");
oprops.Add("product", o.product);
oprops.Add("price", o.price);
obj = oprops;
list.Add(obj);
}

Linq to Sql Projection Help

I've reached the end of my Linq rope. Need your help!
Heres my table structure first(all linq to sql objects):
InventoryItems
-ID
-AmtInStock
IventoryKits
-ID
InventoryKits_to_InventoryItems
-InventoryItemID
-InventoryKitID
So i need to do a projection like the following
var q2=from k in GetAllKits()//returns IQueryable<InventoryKit>
select new VMPublication()//ViewModel Object
{
ID = k.ID,
Name = k.Name,
WebAmountInStock = ,//need to get the Min() AmtInStock from InventoryItems here
ItemCode = k.ItemCode,
WebAmountOrdered = k.AmtOrdered.ToString(),
WebReminderAmount = "",
WebAmountWarning="",
Type = "Kit"
};
i have no idea how to get that Min() of InventoryItem's AmtInStock in that query.
Please help! Very Appreciated!
I'm guessing at your association names, but try something like:
var q2=from k in GetAllKits()//returns IQueryable<InventoryKit>
select new VMPublication()//ViewModel Object
{
ID = k.ID,
Name = k.Name,
WebAmountInStock = (from i in k.InventoryKits_to_InventoryItems
select i.InventoryItem.AmtInStock).Min(),
ItemCode = k.ItemCode,
WebAmountOrdered = k.AmtOrdered.ToString(),
WebReminderAmount = "",
WebAmountWarning="",
Type = "Kit"
};

Resources