Update multiple values to object list in c# - c#

How to update multiple property of object in list?
foreach(emp e in emps){
list1.Where(x => x.ID == e.ID && x.Salary < 5000).FirstOrDefault().Level = B;
list1.Where(x => x.ID == e.ID && x.Salary < 5000).FirstOrDefault().Hike = e.Hike;
list1.Where(x => x.ID == e.ID && x.Salary < 5000).FirstOrDefault().Salary = (e.Hike + 100)*e.Salary/100 ;
}
I dont want to use multiple in-line query for each field. Also it should update same single object.
Note : e.ID is not unique key. list1 can contain duplicate Ids

You need to query your list only once
foreach (emp e in emps)
{
var item = list.FirstOrDefault(x => x.ID == e.empID && x.Salary > 5000);
if (item != null)
{
item.Level = B;
item.Hike = e.Hike;
item.Salary = (e.Hike + 100) * e.Salary / 100;
}
}

After giving lots of try. Looks like these will work :
foreach(emp e in emps){
int index = list1.FindIndex(x => x.ID == e.ID && x.Salary < 5000);
if(index != -1)
{
list1[index].Level = 'B';
list1[index].Hike = e.Hike;
list1[index].Salary = (e.Hike + 100)*e.Salary/100;
}
}
What you guys feel ?

Replace Foo with your class
foreach (emp e in emps)
{
if (list.FirstOrDefault(x => x.ID == e.empID && x.Salary > 5000) is Foo f)
{
f.Level = B;
f.Hike = e.Hike;
f.Salary = (e.Hike + 100) * e.Salary / 100;
}
}

I wanted a solution that updates the object in place, which I suspect the OP wants too.
int i = yourList.FindIndex(x => x.ID == "123" && x.Salary < 5000);
if (i > 0) {
yourList[i].Level = "foo";
yourList[i].Hike = "bar";
}

No explicit search, no nested loops: (if ID is your primary Key)
foreach(item in list.Join(emps, x=>x.ID, e=>e.empID, (l,e)=> (l,e)).Where(x => x.l.Salary > 5000))
{
item.l.Level = B;
item.l.Hike = item.e.Hike;
item.l.Salary = (item.e.Hike + 100) * item.e.Salary / 100;
}
Append .OfType() if you need to.

Related

How to use and if statement in linq Entity framework c#

I am declaring this variable to get data from my database(example)
var products = _context.Products();
and I need to use like this example
if(ctId == -1)
{
// get project list
var products = _context.Products().where(a => a.categoryId == 2);
}
else
{
//get category list
var products = _context.Products().where(a => a.categoryId == 1);
}
but my problem how to declare var products
to using like this
if(ctId == -1)
{
// get project list
products = _context.Products().where(a => a.categoryId == 2);
}
else
{
//get category list
products = _context.Products().where(a => a.categoryId == 1);
}
To the initial problem, you would declare an IQueryable<Product> outside the if scope
IQueryable<Product> products = null;
if(ctId == -1)
products = _context.Products().where(a => a.categoryId == 2);
else
products = _context.Products().where(a => a.categoryId == 1);
However, you could also use a ternary conditional operator
The conditional operator ?:, also known as the ternary conditional
operator, evaluates a Boolean expression and returns the result of one
of the two expressions, depending on whether the Boolean expression
evaluates to true or false.
The syntax for the conditional operator is as follows:
condition ? consequent : alternative
Example
var id = ctId == -1 ? 2 : 1;
var products = _context.Products().where(a => a.categoryId == id);
or potentially
var products = _context.Products().where(a => a.categoryId == (ctId == -1 ? 2 : 1));

Better way calculate percentage from class properties using LINQ

We have the following definition LINQ:
myList.Select(s=> new DtoTest()
{
TotalSamples = myList.Count(c=> c.UserId == s.UserId),
EvaluatedSamples = myList.Count(c=> c.UserId == s.UserId && c.Status == Status.OK)
PercentageRealized = (myList.Count(c=> c.UserId == s.UserId) / myList.Count(c=> c.UserId == s.UserId && c.Status == Status.OK)) * 100
});
Is there a way where you can assign the property value "PercentageRealized" without using the same functions previously used in: "TotalSamples" & "EvaluatedSamples"?
Something like that:
myList.Select(s=> new DtoTest()
{
TotalSamples = myList.Count(c=> c.UserId == s.UserId),
EvaluatedSamples = myList.Count(c=> c.UserId == s.UserId && c.Status == Status.OK)
PercentageRealized = (TotalSamples / EvaluatedSamples) * 100 //<-!Not possible!
});
Any other tips?
Change the function delegate to use the already calculated values
myList.Select(s => {
var result = new DtoTest() {
TotalSamples = myList.Count(c => c.UserId == s.UserId),
EvaluatedSamples = myList.Count(c => c.UserId == s.UserId && c.Status == Status.OK)
};
result.PercentageRealized = (result.TotalSamples / result.EvaluatedSamples) * 100;
return result;
});
If you were using an anonymous type this would be more complicated, but since DtoTest is a class, you could always move your math into the property.
public class DtoTest
{
public float PercentageRealized
{
get { return (TotalSamples / EvaluatedSamples) * 100; }
}
}
If PercentageRealized is that simple calculations, why not have the calculation in the property in the class, something like this inside the class DTOTest:
public float PercentageRealized => (TotalSamples / EvaluatedSamples) * 100;
What you are doing seems extremely questionable to me - you are making multiple passes over the source data to re-compute the same thing over and over again (per occurrence of UserId), when it seems like what you should want is to compute once per UserId, like so:
var ans2 = myList.GroupBy(s => s.UserId)
.Select(sg => {
var ts = sg.Count();
var es = sg.Count(c => c.Status == Status.OK);
return new DtoTest { UserId = sg.Key, TotalSamples = ts, EvaluatedSamples = es, PercentageRealized = (int)(100.0 * ts / es) };
});
Also, your percentage calculation will use C# integer division and not be close to correct, unless you convert to double first. You can cast back to int after the math.
If you really intended to return multiple results, and want to be efficient (and since I love extension methods), creating an extension method to count chained predicates for one pass:
public static class IEnumerableExt {
public static (int Cond1Count, int Cond2Count) Count2Chained<T>(this IEnumerable<T> src, Func<T, bool> cond1, Func<T, bool> cond2) {
int cond1Count = 0;
int cond2Count = 0;
foreach (var s in src) {
if (cond1(s)) {
++cond1Count;
if (cond2(s))
++cond2Count;
}
}
return (cond1Count, cond2Count);
}
}
Now you can count the sub-values in one pass and compute the third value:
var ans3 = myList.Select(s => {
var (ts, es) = myList.Count2Chained(c => c.UserId == s.UserId, c => c.Status == Status.OK);
return new DtoTest { UserId = s.UserId, TotalSamples = ts, EvaluatedSamples = es, PercentageRealized = (int)(100.0 * ts / es) };
});
Of course, depending on the size of myList, you may still be better off calculating each answer once and then repeating them for the final answer:
var ansd = myList.GroupBy(s => s.UserId)
.Select(sg => {
var ts = sg.Count();
var es = sg.Count(c => c.Status == Status.OK);
return new { sg.Key, ts, es };
})
.ToDictionary(ste => ste.Key, ste => new DtoTest {
UserId = ste.Key,
TotalSamples = ste.ts,
EvaluatedSamples = ste.es,
PercentageRealized = (int)(100.0 * ste.ts / ste.es) });
var ans4 = myList.Select(s => ansd[s.UserId]);
first project to a tuple then project to your custom object:
myList.Select(s => (tSample: myList.Count(c=> c.UserId == s.UserId),
eSample : myList.Count(c=> c.UserId == s.UserId && c.Status == Status.OK)))
.Select(x => new DtoTest
{
TotalSamples = x.tSample,
EvaluatedSamples = x.eSample,
PercentageRealized = (x.tSample / x.eSample) * 100
});
or use an anonymous type:
myList.Select(s => new
{
tSample = myList.Count(c=> c.UserId == s.UserId),
eSample = myList.Count(c=> c.UserId == s.UserId && c.Status == Status.OK)
})
.Select(x => new DtoTest
{
TotalSamples = x.tSample,
EvaluatedSamples = x.eSample,
PercentageRealized = (x.tSample / x.eSample) * 100
});

Merge two Ordering Results into one result in linq with C#

I order two types of query. I want to show the result as one. if the first query and second query have count these both are merge and show the results of one. So i have created 3 list like jobs, jobs1, jobs2. I am getting values into jobs1 and jobs2. Then i have assigned using union into jobs3
Code
IQueryable<Job> jobs = _repository.GetJobs();
IQueryable<Job> jobs1 = _repository.GetJobs();
IQueryable<Job> jobs2 = _repository.GetJobs();
List<int> lstId = null;
List<int> lstUpdatedListId = null;
List<int> lstConId=null;
var order = _db.GetOrderDetails().Where(od => od.Masters.Id != null && od.OrderId == od.Master.OrderId && od.Master.Status == true && od.ValidityTill.Value >= currentdate).OrderByDescending(od => od.ValidityTill).Select(ord => ord.Master.Id.Value);
var order1 = _vasRepository.GetOrderDetails().Where(od => od.Masters.ConId != null && od.OrderId == od.Masters.OrderId && od.Masters.PaymentStatus == true && od.ValidityTill.Value >= currentdate).OrderByDescending(od => od.ValidityTill).Select(ord => ord.Masters.ConId.Value);
var updatedVacancyList = _repository.GetJobs().Where(c => c.UpdatedDate != null && updateFresh <= c.UpdatedDate).Select(c => c.Id);
if (order1 .Count() > 0)
{
lstConId = order1.ToList();
Func<IQueryable<Job>, IOrderedQueryable<Job>> orderingFunc = query =>
{
if (order1.Count() > 0)
return query.OrderByDescending(rslt => lstConId.Contains(rslt.Con.Id)).ThenByDescending(rslt=>rslt.CreatedDate);
else
return query.OrderByDescending(rslt => rslt.CreatedDate);
};
jobs1 = orderingFunc(jobs);
}
if (order.Count() > 0)
{
lstId = order.ToList();
lstUpdatedJobsListId = updatedVacancyList.ToList();
Func<IQueryable<Job>, IOrderedQueryable<Job>> orderingFunc = query =>
{
if (order.Count() > 0)
return query.OrderByDescending(rslt => lstId.Contains(rslt.Id)).ThenByDescending(rslt => lstUpdatedJobsListId.Contains(rslt.Id)).ThenByDescending(rslt=>rslt.CreatedDate);
if (updatedVacancyList.Count() > 0)
return query.OrderByDescending(rslt => lstUpdatedJobsListId.Contains(rslt.Id)).ThenByDescending(rslt => rslt.UpdatedDate);
else
return query.OrderByDescending(rslt => rslt.CreatedDate);
};
jobs2 = orderingFunc(jobs);
}
jobs = jobs1.Union(jobs2);
and i am getting an error while run the application as follows,
The text data type cannot be selected as DISTINCT because it is not comparable.
I need help to rectify this issue. I want to order in descending also.
One of your columns in Database is "Text" type. Convert it to varchar(MAX)

Remove an item from a LINQ collection

I think I am putting my question correctly :)
I am querying the database using LINQ to retrieve some data. Please find the code below.
var leadtasktype = _context.LeadTypeTaskTypes.Where(l => l.LeadTypeId == item.Value);
foreach(LeadTypeTaskType l in leadtasktype){
if (l.TaskTypeId == 21)
{
//I need to remove an item which has the tasktype id 21
}
}
As I mentioned in the comments, I need to remove items from the leadtasktype based on my if condition. How do I do this?
This would seem very like another filter condition:
var leadtasktype = _context.LeadTypeTaskTypes
.Where(l => l.LeadTypeId == item.Value)
.Where(l => l.TaskTypeId != 21); // Exclude ID = 21.
var leadtasktype = _context.LeadTypeTaskTypes.Where(l => l.LeadTypeId == item.Value && l.LeadTypeId != 21);
Just leave them out of your set:
var leadtasktype = _context.LeadTypeTaskTypes
.Where(l =>
l.leadTypeId != 21 &&
l.LeadTypeId == item.Value
);
Is it this what you want ?
var leadtasktype = _context.LeadTypeTaskTypes.RemoveAll
(l => l.LeadTypeId == item.Value && l.LeadTypeId == 21);
var leadtasktype = _context.LeadTypeTaskTypes
.Where(l => l.LeadTypeId == item.Value
&& l.TaskTypeId != 21); // Exclude ID = 21.
var leadtasktype = _context.LeadTypeTaskTypes.Where(l => l.LeadTypeId == item.Value);
for (var i = 0; i < leadtasktype.Count; i++)
{
if (leadtasktype[i].TaskTypeId == 21)
{
leadtasktype.RemoveAt(i);
}
}
var leadtasktype = _context.LeadTypeTaskTypes.Where(l => l.LeadTypeId == item.Value);
var newData = leadtasktype;
foreach(LeadTypeTaskType l in leadtasktype){
if (l.TaskTypeId == 21)
{
newData.Remove(l);
}
}

Linq Complex OrderBy by Props attributes

I have a class with some props tagged with some attributes. I want to display them on a specific order. So far I can put them in a order, but not on the order that I want.
Here is a simple example of the props with the attributes
[IncludeInEditor]
[IsInPk]
ID
[IncludeInEditor(IsReadOnlyOnModify=true)]
Name
[IncludeInEditor]
Address
[IncludeInEditor]
DOB
The order that I want is:
1st - Props with IsInPk attribute
2nd - Props with IncludeInEditor(IsReadOnlyOnModify=true)
3rd - Props with IncludeInEditor
So far I got this with no sucess and not 100% done (still missing the IsReadOnlyOnModify=true part)
var properties =
item.GetType().GetProperties()
.Where(p => p.GetCustomAttributes(true)
.OfType<IncludeInEditorAttribute>()
.Count() > 0)
.Select (x => new
{
Property = x,
Attribute = (IsInPkAttribute)Attribute.GetCustomAttribute(x, typeof(IsInPkAttribute), true)
})
.OrderBy(x => x.Attribute != null ? 1 : -1)
.Select(x => x.Property)
.ToArray();
You can create your own IComparer<T> implementation to compare the attributes on each property:
public class AttributeComparer : IComparer<Attribute>
{
public int Comparer(Attribute x, Attribute y)
{
if(x == null) return y == null ? 0 : -1;
if(y == null) return 1;
if(x is IsInPkAttribute) return (y is IsInPkAttribute) ? 0 : 1;
else if(y is IsInPkAttribute) return -1;
else
{
xa = (IncludeInEditorAttribute)x;
ya = (IncludeInEditorAttribute)y;
if(xa.IsReadOnlyOnModify == ya.IsReadOnlyOnModify) return 0;
else return x.IsReadOnlyOnModify ? 1 : -1;
}
}
}
Then your query becomes:
var properties = item.GetType().GetProperties()
.Where(p => p.GetCustomAttributes(true)
.OfType<IncludeInEditorAttribute>()
.Any())
.Select (x => new
{
Property = x,
Attribute = Attribute.GetCustomAttribute(x, typeof(IsInPkAttribute), true) ?? Attribute.GetCustomAttribute(x, typeof(IncludeInEditorAttribute, true))
})
.OrderBy(x => x.Attribute, new AttributeComparer())
.Select(x => x.Property)
.ToArray();
After the help of Lee, finally it´s working. The correct code is:
var properties =
item.GetType().GetProperties()
.Where(p => p.GetCustomAttributes(true)
.OfType<IncludeInEditorAttribute>()
.Any())
.Select(x => new
{
Property = x,
Attribute = Attribute.GetCustomAttribute(x, typeof(IsInPkAttribute), true)
?? Attribute.GetCustomAttribute(x, typeof(IncludeInEditorAttribute), true)
})
.OrderBy(x => x.Attribute, new IncludeInEditorAttributeComparer())
.Select(x => x.Property)
.ToArray();
This code that Lee sent, I made a little change.
public class IncludeInEditorAttributeComparer : IComparer<Attribute>
{
public int Compare(Attribute x, Attribute y)
{
//In this case we can assume that
//won´t have null values
if (x is IsInPkAttribute && !(y is IsInPkAttribute))
return -1;
else if (y is IsInPkAttribute && !(x is IsInPkAttribute))
return 1;
else
{
bool xa = (x is IncludeInEditorAttribute ? (x as IncludeInEditorAttribute).IsReadOnlyOnModify : false);
bool ya = (y is IncludeInEditorAttribute ? (y as IncludeInEditorAttribute).IsReadOnlyOnModify: false);
if (xa && !ya)
return -1;
else if (ya && !xa)
return 1;
else
return 0;
}
}
}

Categories