Modify property value using LINQ - c#

I have following classes:
public class QualifyResponse
{
public Message[] MessageList{get; set;}
}
public class Message
{
public MessageDetail[] MessageDetailList{get; set;}
public string MessageStatus{get; set;}
public string ProviderCode{get; set;}
}
public partial class MessageDetail
{
public string MessageCategory{get; set;}
public string MessageCode{get; set;}
public string MessageSeverity{get; set;}
public string MessageText{get; set;}
}
What I want is, For all the MessageDetailList, if the messageCode is equal to "status" then assign its messageText value to "Complete" after this query
I tried the following LINQ, but it didnt work i.e the MessageDetailList objects having MessageCode = "status" didn't have MessageText = "Complete".
response.MessageList.FirstOrDefault()
.MessageDetailList
.Where(message => message.MessageCode
.ToLower()
.Equals("status"))
.ToList()
.ForEach(status =>
{
status.MessageText = "Complete";
});
What am I doing wrong?

A bit of formatting helps read your code
However this should help and double check the results
Note if your Where clause is correct it WILL update your
MessageText providing there isn't some funky setter going on
var message = response.MessageList.FirstOrDefault();
var messageDetails = message.MessageDetailList
.Where(message => message.MessageCode.ToLower() == "status")
.ToList();
messageDetails.ForEach(status => status.MessageText = "Complete");
messageDetails.ForEach(status => Debug.WriteLine(status.MessageText));
Update
This all should work fine
Try a foreach instead
Try putting a try catch around it all
Try checking the result immediately after you are setting it.
If this from Ef try `SaveChanges'
We don't know how you are checking your results

Related

How to remove list object from an item in List?

I have a class:
public class FlightDetails
{
public string FlightId {get; set;}
public string PilotName {get; set;}
public string Area {get; set;}
public string Country {get; set;}
}
Here sending response:
public async Task<List<FlightDetails>> GetFlightAsync(string FlightId)
{
//
var flights = new List<FlightDetails>();
flights = response.AllFlights;
flights = flights.Where(x => x.FlightId.Contains(FlightId)).ToList();
//
return flights;
}
Getting List here and data is filled but issue is don't want FlightId and Country in the response which I am sending. How to remove this objects in the List? Finally in the List item there should be only PilotName and Area.
Update:
I forgot the following line before the flights = response.AllFlights;
var request = await _rest.Get<WorldFlights>(url + $"?FlightId={FlightId}");
You will need to create another object, and map there only the properties you want. For example:
public class FlightDetailsResponse
{
public string PilotName {get; set;}
public string Area {get; set;}
}
And then in the function:
public async Task<List<FlightDetailsResponse>> GetFlightAsync(string FlightId){
var flights = response.AllFlights;
var flightResponses = flights
.Where(x => x.FlightId.Contains(FlightId).ToList())
.Select(x => new FlightDetailsResponse{
PilotName = x.PilotName,
Area = x.Area
});
return flightResponses;
}
This way the response will only contain the PilotName and Area fields.
PD: What I wrote might not compile because of missing commas or something like that. Sorry, it has been some time since I last wrote C#, but the idea is that.

How to update a property of an complexObj. inside a Document inside a List<complexObj>? MongoDB C# net.Driver

how to update one property of a document in MongoDb with C# net.Driver.
My data model in C# looks like this:
public class MyMediListsWrapper
{
[BsonId]
public Guid Id { get; set; }
public DateTime Datum { get; set; }
public bool IsActiv { get; set; }
public List<Medi> MediLsts { get; set; }
}
public class Medi
{
public Guid Id { get; set; }
public string Name { get; set; }
public string Typ { get; set; }
public string Vmax { get; set; }
}
Now I want to update only one property of one Obj. (Vmax='Test') of the nested List MediLsts.
I wand to filter the collection MyMediListsWrapper by SingleOrDefault IsActiv=true and then I want to filter 'in this Document' the Medi-Obj. from the nested List inside by Guid='XcPwoEaB8Ey7XR1AEB+fLQ=='
and then update Vmax='Test'.
I have a little bit of code, but it doesn't achieve what I want. I have trouble to do the filter first for IsActiv and then filter inside of that Document again for a different property. And I don't know how to write the code for the update later (if found). Thx for help.
My Code:
var db = client.GetDatabase(MySecret.MyMongoDbName);
var myMediListsWrapper = db.GetCollection<MyMediListsWrapper>(MySecret.MyWrapperColName);
var filter = Builders<MyMediListsWrapper>.Filter;
var filterColAndFilterLstObj = filter.And(
filter.Eq(x => x.IsActiv, true),
filter.ElemMatch(x => x.MediLsts, lst => lst.Id == mySearchGuid));
//Just a Test -- I want to UPDATE a property NOT find a entry
//and this is WRONG because it give me a obj of the outer class not the Medi-Obj.
var result = await myMediListsWrapper.Find(filterColAndFilterLstObj).SingleOrDefaultAsync(); ```
the following update command should do the trick:
await collection.UpdateOneAsync(
filter: w => w.IsActiv && w.MediLsts.Any(m => m.Id == mySearchGuid),
update: Builders<MyMediListsWrapper>.Update.Set(m => m.MediLsts[-1].Vmax, "TEST"));
the thing to note here is the [-1] array/list index above.
the driver translates that to the following $set operation:
$set: { "MediLsts.$.Vmax" : "TEST" }
-1 index position is something special the mongo driver uses to denominate $ which is the first positional operator.
i.e. update the first array element that qualifies for the $elemMatch condition of the filter.
.MediLsts.Any(...) is the LINQ equivalent of filter.ElemMatch(...)

C# driver 2.0 Mongodb UpdateOneAsync

public class Student
{
public long StudentId {get; set;}
public string Fname {get; set;}
public string Lname {get; set;}
public List<ObjectId> CoursesList {get; set;}
public int IQ {get;set;}
}
public class Courses
{
[BsonId]
public ObjectId Id { get; set; }
public string CourseNumber{get; set;}
public string CourseName{get; set;}
}
How do I add/append a courser Id to Course list(which may be null for the first time) of a Student object
PS: I know how to set a field using the below command. I am hoping it is on similar lines for the above problem
await StudentCollection.UpdateOneAsync(a => a.StudentId == studentId, Builders<Student>.Update.Set( a => a.IQ,90));
As you've already discovered, the C# code to use $addToSet is:
var filter = Builders<Student>.Filter.Eq(s => s.StudentId, studentId);
var update = Builders<Student>.Update.AddToSet(s => s.CoursesList, courseId);
var result = await collection.UpdateOneAsync(filter, update);
However, $addToSet is not going to work if the CourseList member has been stored in the collection as a null. The server requires that the existing value for $addToSet be an array (it can be an empty array).
The easiest solution is to just store an empty list for CoursesList instead of a null when there are no courses.
This is working for me. When you define "List" like this, it will be empty and works with AddToSet/Push methods.
public List<ObjectId> CoursesList = new List<ObjectId>();
The only case that you have to pay attention is when the array CourseList is null, in this case you have to use the code below (see also here):
var newListOfObject = new List<ObjectId>(){...}
await StudentCollection.UpdateOneAsync(a => a.StudentId == studentId, Builders<Student>.Update.Set( a => a.CoursesList, newListOfObject));
Otherwise you can use AddToSet or Push like explain in the other answers.

Filter Sub-Collection of Collection

I have the following classes:
class Customer
{
public int IdCustomer {get; set}
public string Name {get; set;}
public virtual ICollection<Expertise> Expertises {get; set;}
}
class Expertise
{
public int IdExpertise {get; set;}
public string Description {get; set;}
public virtual ICollection<SubExpertise> SubExpertises {get; set;}
}
class SubExpertise
{
public int IdSubExpertise { get; set;}
public int IdExpertise {get; set;}
public string Description {get; set;}
public virtual Expertise Expertise {get; set;}
}
How I can filter a SubExpertise using a IQueryable, and keep the filter condition? Basically I want to filter by SubExpertise, but keeping the possibilty to add more filters in the query
Example: I wanna all customers that have a SubExpertise 'x' or 'y'. Keep in mind that SubExpertise is a sub-collection of a collection (Expertise). And that I can have new filters after this.
I think you're after a method to build the expressions dynamically. You could use a predicate builder to do the job. My favorite is this one.
Using this little gem you can do this:
var pred = PredicateBuilder.Create<SubExpertise>(s => s.Description == "x");
pred = pred.Or(s => s.Description == "y");
var customers = db.Customers
.Where(c => c.Expertises
.Any(e => e.SubExpertises.AsQueryable()
.Any(pred)));
e.SubExpertises must be cast to IQueryable because it's compile-time type is ICollection, and the extension method Any that fits ICollection doesn't accept an Expression but a Func, so it doesn't compile.
I use a pattern like this for resuable filters, defining the filters as Expressions
public static class SubExpertiseFilter
{
public static Expression<SubExpertise, bool> XorY =
se => se.Description == "X" || se.Description == "Y";
}
Then if I want to apply it:
public IQueryable<Expertise> ApplyXorYFilter(IQueryable<Expertise> expertises, bool appyXorY)
{
if(applyXorY)
{
expertises = expertises.Any(e => e.Subexpertises.AsQueryable().Any(SubExpertiseFilter.XorY);
}
return expertises;
}
Or just do it inline where you need it.
The "AsQueryable" is needed to use the expression inside another expression so that EF is happy with it, otherwise the compiler expects a function there and that isn't something EF can turn into SQL.
Suppose you have a list customers
var filteredCustomers = from customer in customers
where customer.Expertises.Any(e => e.Subexpertises.Any(s => IsXOrY(s)))
select customer;
You can add any filter conditions in IsXOrY: (and you should rename it)
bool IsXOrY(SubExpertise subExpertise)
{
check if the SubExpertise is 'x' or 'y'
check if the SubExpertise meets other criteria
return true if this SubExpertise meets all your criteria
}

Convert cypher query to c#

I have two tables:
User
Name
Surname
Phone
number
type_of_number
var myList = ((IRawGraphClient) client).ExecuteGetCypherResults<**i_need_class_to_save_it**>(
new CypherQuery("match (a:User)-[r]->(b:Phone) return a,collect(b)", null, CypherResultMode.Set))
.Select(un => un.Data);
How create correct collection to save data?
It sounds like you haven't read https://github.com/Readify/Neo4jClient/wiki/cypher or https://github.com/Readify/Neo4jClient/wiki/cypher-examples. You really should start there. It helps to read the manual. I don't just write it for fun.
For your specific scenario, let's start with your Cypher query:
MATCH (a:User)-[r]->(b:Phone)
RETURN a, collect(b)
Now, we convert that to fluent Cypher:
var results = client.Cypher
.Match("(a:User)-[r]->(b:Phone)")
.Return((a, b) => new {
User = a.As<User>(),
Phones = b.CollectAs<Phone>()
})
.Results;
You can then use this rather easily:
foreach (var result in results)
Console.WriteLine("{0} has {1} phone numbers", result.User.Name, result.Phones.Count());
You will need classes like these, that match your node property model:
public class User
{
public string Name { get; set; }
public string Surname { get; set; }
}
public class Phone
{
public string number { get; set; }
public string type_of_number { get; set; }
}
Again, please go and read https://github.com/Readify/Neo4jClient/wiki/cypher and https://github.com/Readify/Neo4jClient/wiki/cypher-examples.
Add a .ToList() at the end of your command?
Like this :
var myList = ((IRawGraphClient) client).ExecuteGetCypherResults<**i_need_Collection**>(
new CypherQuery("match (a:User)-[r]->(b:Phone) return a,collect(b)", null, CypherResultMode.Set))
.Select(un => un.Data).ToList();

Categories