How can I update specific element in List<T>? - c#

I am writing a C# console application where I have a class Customer as following:
public class Customers
{
public string Name { get; set; }
public string UserID { get; set; }
public int Pin { get; set; }
public int AccountNo { get; set; }
public string AccountType { get; set; }
public int Balance { get; set; }
public string Status { get; set; }
}
I am storing the customer data in text file as below ("Customers.txt"):
[
{"Name":"Jack Willson","UserID":"Jack21","Pin":12345,"AccountNo":1,"AccountType":"Savings","Balance":2000,"Status":"Active"},
{"Name":"Mary Poppins","UserID":"mary8912","Pin":67890,"AccountNo":2,"AccountType":"Savings","Balance":4567,"Status":"Active"},
{"Name":"Harry Potter","UserID":"Harry45","Pin":12345,"AccountNo":4,"AccountType":"Savings","Balance":12000,"Status":"Active"}
]
I am reading this file as :
List<Customers> list = ReadFile<Customers>("Customers.txt");
I wish to update a specific customer field based on user input. If user leaves the field input blank then the field information remains unchanged.
The program will ask user to enter the AccountNo for which he wishes to update an information.
Then program will display each property like UserID, AccountType, Status. If the user doesnot enter any input for any of the property then information remains unchanged.
I was trying to save the input from user in new Customer() object but couldn't proceed to compare it or save it in List<customers> where i am storing the data from text file.
How can I achieve this?

Something like this should do the trick.
var accountNum = 2; //I'm going to assume you get this from Console.ReadLine() and validate it.
//Find the customer with that account number...
var query = list.Where(c => c.AccountNo == accountNum);
if (!query.Any()
Console.WriteLine("Customer not found.");
var customer = query.First();
//Now you can manipulate the customer object as you please
//In your situation I think you want to loop through the properties they can change and set them.
customer.Name = "Some new name";
customer.Pin = 1234;
//Save the updated information back to the text file however you currently do this
Hopefully this helps :)

You can look into this solution using Linq:
int acNo = ReadAccountNumber();
IEnumerable<Customers> results = myList.Where(c => c.AccountNo == acNo);
if you are sure that AccountNo are unique then results will hold just one element. You can update the first element if that exists.
Customers cust = myList.First(c => c.AccountNo == acNo);
cust?.Name = newName;

Related

creating a list of Id's from database. C#

Im trying to generate a random ID number so when the user clicks a button it redirects to a random artist. I was able to do it and it works quite well with the code below.
var artists = _context.Artists;
var totalArtists = artists.Count();
Random randomArtistNumber = new Random();
int randomArtistID = randomArtistNumber.Next(1, totalArtists + 1);
if (button.Equals("btnArtist"))
{
return RedirectToAction("Details", "ArtistModels", new { id = randomArtistID.ToString() });
}
The problem here is that if the user deletes an artist then im going to have an ID number that no longer exists in the random list created above. How would I go about creating a List<> of all ArtistID's in the Artist Table? It would be much better to just pick a random number from within a list of active ID's
ArtistModel below
public class ArtistModel
{
[Key]
public int ArtistID { get; set; }
public string ArtistName { get; set; }
public string CountryOfOrigin { get; set; }
public int SubgenreID { get; set; }
public SubgenreModel Subgenre { get; set; }
public ICollection<AlbumModel> Albums { get; set; }
}
I'm guessing you are using Entity Framework?
You should be able to get a list of ids from your artists by doing something like this.
var artistIds = artists.Select(a => a.Id).ToList();
To do that correctly you'd need to ensure that you were always loading all artists from the context.
Might be better if you random function had a limit, like maybe randomly select from the first 200 artists or something.
Since you already have the artists, what you can actually do is get a random artist, it wouldnt be much different from what you have
Something like:
int randomArtistIndex = randomArtistNumber.Next(1, totalArtists);
var artist = artists[randomArtistIndex]
and then
return RedirectToAction("Details", "ArtistModels", new { id = artist.ArtistID.ToString() });

Elegant way to map some properties in one List based on Id from another List in C#

I have a User List and Branch List. One Branch can have multiple User. I need to assign few properties in User from Branch based on BranchId. Here are my classes.
User:
public class User
{
public Guid Id { get; set; }
public bool Active { get; set; }
public Guid BranchId { get; set; }
public string BranchName { get; set; }
}
Branch:
public class Branch
{
public Guid Id { get; set; }
public bool Active { get; set; }
public string BranchName { get; set; }
}
Here is what I have tried,
foreach (var user in vm)
{
var branch = branches.Single(b => b.Id.Equals(user.BranchId));
user.BranchName = branch.BranchName;
}
Right now this works, but I feel this as not a good solution as to iterate users and get branch everytime for that user and assign that. May be multiple users in the list can have same BranchId in that case it happens like I'm reading the same branch again and again. Any better solutions using LINQ or this can be improved in any ways? please assist.
Well, you could create a dictionary mapping from branch ID to brand name:
var branchIdToBrandName = branches.ToDictionary(b => b.Id, b => b.BrandName);
foreach (var user in users)
{
user.BrandName = branchIdToBranchName[user.BranchId];
}
That's assuming there's exactly one branch per branch ID, and that every user's branch ID is covered. If you need to do the same for other properties, you'd probably want to just map branch ID to branch, rather than straight to brand name, e.g.:
var branchIdToBranch = branches.ToDictionary(branch => branch.Id);
foreach (var user in users)
{
user.BrandName = branchIdToBranch[user.BranchId].BrandName;
}

MongoDB and Asp Core update only a key: value pair instead of whole model

In our app we have a user model linked to a mongoDB database. My question is about modifying only a value from key/value pair inside a given user data (of course using the User ID).
Here is my simple model:
public class User
{
[BsonId]
public string Id { get; set; }
public string email { get; set; } = string.Empty;
public bool hasAcceptedTerms { get; set; } = false;
public int state { get; set; } = 0;
public int UserId { get; set; } = 0;
public IList<UserFile> SubmittedFiles { get; set; }
}
public class UserFile
{
public int fileID { get; set; }
public bool hasFile { get; set; }
}
On our app, after authenticate the user for the first time, we create his entry in the Mongo Database using
public async Task AddUser(User item)
{
await _context.Users.InsertOneAsync(item);
}
After his first login we want to update the fact he accepted Terms: by doing so we want to change hasAcceptedTerms to true and move the state key from 0 to 1.
For the moment in our Repository we have something like:
public async Task<UpdateResult> UpdateUser(string id, User item)
{
return await _context.Users
.ReplaceOneAsync(n => n.Id.Equals(id)
, item
, new UpdateOptions { IsUpsert = true });
}
But by doing so we must provide a full item corresponding to our model.
I don't find any way to create a function which I could use like:
UdateUserData(string id, string data, bool newvalue);
For example call UpdateUserData('user1objectidhash', 'hasAcceptedTerms', true) would modify the correct value for the user identified by his ObjectID Id.
First problem: is typing data as string a good idea/unique solution? I don't find my function call being elegant by typing the data key as a string.
2nd: I don't know what will be the type of newvalue because it will depend on what is the data I want to modify. Can I detect it from model?
3rd: I don't know the correct Mongo.Driver function which can process this update.
Could you give me some cues and tips?
If you just want to update not whole object, but some properties it's possible to do this Update command:
collection.UpdateOneAsync(x=>x.Id ==id,
Builders<User>.Update.Set(u=>u.hasAcceptedTerms, false)
.Set(u=>u.state, 1));
I assume, that collection is your IMongoCollection<User> , that you mean with _context.Users

Creating custom linq column names in list

We are returning a generic List to a GridView, which then auto generates columns to show a report:
//Generate List
List<Stock> allStock = blStock_Collection.getAll();
//export custom view for report datagrid
return (from myStock in allStock
select new
{
myStock.Category,
myStock.Description,
myLowStock.UnitPrice,
myLowStock.CurrentQuantity
});
Our client has asked that we now provide multi-lingual support on our site (English & Polish), specifically the column headers on grids. We would therefore need to get rid of the auto generate option on all our data grids, and add in the translations manually for each column.
I was wondering is there a way to do this when generating the datasource, which would save us a hell of a lot of time, e.g. changing this line:
myStock.Category,
to something like:
languagePack.Category = myStock.Category,
This is of course throwing a 'Invalid anonymous type member declarator' error. Any advice?
Maybe I misread something, but if you just want to put your language into it (LanguagePack is just a class holding your values):
class LanguagePack
{
public int Category { get; set; }
public string Description { get; set; }
public decimal UnitPrice { get; set; }
public int CurrentQuantity { get; set; }
public int LanguageName { get; set; }
}
return (from myStock in allStock
select new LanguagePack
{
Category = myStock.Category,
Description = myStock.Description,
UnitPrice = myLowStock.UnitPrice,
CurrentQuantity = myLowStock.CurrentQuantity,
LanguageName = "Polish" // or english or whatever... maybe LanguageId or something corresponding to your model
});

MongoDB best practice for referencing

I'm wondering what the best practice for modelling by using references would be given situation under. I'm using MongoRepository library.
public class User : Entity
{
publis string Id { get; set; }
public string Email { get; set; }
public string Password { get; set; }
}
public class Post : Entity
{
public string Id { get; set; }
public string Title { get; set; }
public string Summary { get; set; }
public DateTime Added { get; set; }
public User Owner { get; set; }
}
When storing the Post I want only reference to Owner (User) object instead of whole object underlying.
Currently I'm doing it like this, not knowing of better way...
var post = new Post
{
Title = "Example title",
Summary = "asd asd",
Added = DateTime.Now,
Owner = new User { Id = "someExistingUserId" }
};
postRepository.Update(post); //Save
..
//Then to get the post
var post = postRepository.GetById("previouslySavedPostId");
post.Owner = userRepository.GetById(post.Owner.Id);
return post;
userRepository and postRepository are of MongoRepository type.
Is this the correct approach to solving my problem using MongoDB with C#/MVC(4)?
You can use MongoDBRef object instead of User object.
public class Post : Entity
{
public string Id { get; set; }
public string Title { get; set; }
public string Summary { get; set; }
public DateTime Added { get; set; }
public MongoDBRef Owner { get; set; }
}
Then you can:
var mongo = new Mongo(config.BuildConfiguration());
mongo.Connect();
var DB = mongo.GetDatabase(_dataBaseName)
var post = new Post();
post.Owner = new MongoDBRef("User", userId); // First parameter is a mongoDB collection name and second is object id
// To fetch object referenced by DBRef you should do following
var owner = DB.FollowReference<User>(post.Owner);
Mongo is a document database and if you are used to using sql server it requires a slightly different way of thinking.
As you don't want the user password details in every single post, the way i would probably do it is to create a new class to contain any user info that might be required to display a post.
public class PostOwnerInfo
{
public string UserId { get; set; }
public string Name { get; set; }
}
Update your post entity, replacing the Owner property with an OwnerInfo property, of type PostOwnerInfo.
Then when you create a new post, do the following.
var user = userRepository.GetById(someExistingUserId);
var post = new Post
{
Title = "Example title",
Summary = "Example summary",
Added = DateTime.Now,
OwnerInfo = new PostOwnerInfo
{
UserId = user.Id,
Name = user.Name
}
};
postRepository.Update(post);
This way when you query for a post it will have all the user info that you require to display the post in it's OwnerInfo property with no further queries required.
var post = postRepository.GetById(previouslySavedPostId);
// post.OwnerInfo will contain user info
There is a certain amount of data redundancy, but in an document database this is how i would do it.
If you need the full user info for any reason just do a seperate query for it as you were doing before.
The idea is that you store all the user info you need for a post in a child document of the post, so you shouldn't need to do a seperate query for the user.
If the user data chages, just update the UserInfo field on all posts made by your user.
Your user data will rarely change, but you will query for posts very often.

Categories