Updating a List record within a record with c# and Linq, looking for something cleaner than add and remove
-
So this is really a MongoDb document class for a category, that has subCategories. Below is an example of how the data is structured. For some reason, I'm drawing a blank on how to do this, or I've never really had a need to do it. I want to update 1 sub category using Linq, so I can just write the whole category document using MongoDb as a ReplaceOneAsync(). But I just can't figure out how. This is in a .Net Core Controller.
{
"_id" : "5d9f97eb29d7b329209b13cb",
"Name" : "Solid State Drives",
"Description": "Great Drive",
"SubCategories" : [
{
"_id" : "5da8a1d7afb5d4084c80c9a4",
"Name" : "NVMe",
"Description" : "Fast Drive"
},
{
"_id" : "5da8a1d7afb5d4084c80c9a4",
"Name" : "2.5\" Form Factor",
"Description" : "Small Drive"
}
}I'm thinking this, but VS didn't like the left side.
var cR = GetCategory(cid);
cR.SubCategories.FirstOrDefault(sc => sc.Id == subCategory.Id) = subCategory;
UpdateCategory(cid, cR);I know I can do this, but I would like to preserve the original order.
cR.SubCategories.Remove(subCategory);
cR.SubCategories.Add(subCategory);Or this
var idx = -1;
foreach (var sc in cR.SubCategories)
{
idx++;
if (sc.Id.Equals(subCategory.Id))
{
cR.SubCategories[idx] = subCategory;
}
}I'm just looking for clean 1 liner to do this with if it exist.
If it ain't broke don't fix it Discover my world at jkirkerx.com
-
So this is really a MongoDb document class for a category, that has subCategories. Below is an example of how the data is structured. For some reason, I'm drawing a blank on how to do this, or I've never really had a need to do it. I want to update 1 sub category using Linq, so I can just write the whole category document using MongoDb as a ReplaceOneAsync(). But I just can't figure out how. This is in a .Net Core Controller.
{
"_id" : "5d9f97eb29d7b329209b13cb",
"Name" : "Solid State Drives",
"Description": "Great Drive",
"SubCategories" : [
{
"_id" : "5da8a1d7afb5d4084c80c9a4",
"Name" : "NVMe",
"Description" : "Fast Drive"
},
{
"_id" : "5da8a1d7afb5d4084c80c9a4",
"Name" : "2.5\" Form Factor",
"Description" : "Small Drive"
}
}I'm thinking this, but VS didn't like the left side.
var cR = GetCategory(cid);
cR.SubCategories.FirstOrDefault(sc => sc.Id == subCategory.Id) = subCategory;
UpdateCategory(cid, cR);I know I can do this, but I would like to preserve the original order.
cR.SubCategories.Remove(subCategory);
cR.SubCategories.Add(subCategory);Or this
var idx = -1;
foreach (var sc in cR.SubCategories)
{
idx++;
if (sc.Id.Equals(subCategory.Id))
{
cR.SubCategories[idx] = subCategory;
}
}I'm just looking for clean 1 liner to do this with if it exist.
If it ain't broke don't fix it Discover my world at jkirkerx.com
You can do
public class Jef { public int a; public int b; } public class Test { List list = new List(); private void test1() { list.First().b = 13; list.First(j => j.a == 12).b = 14; } }
when Jef is a class, as list.First() then returns the reference of a Jef object. And when null, it would throw a NullRefExc. You can't when Jef is a struct, as structs are value types, there is no reference or pointer to a value type. With structs the compiler rightfully gives the error: cannot modify the return value of ... because it is not a variable. Furthermore, I'm wondering what you expect from
FirstOrDefault
as a target for assignment: when no items match, the default would be what? where would the new value have to go? :)Luc Pattyn [My Articles] Nil Volentibus Arduum
-
So this is really a MongoDb document class for a category, that has subCategories. Below is an example of how the data is structured. For some reason, I'm drawing a blank on how to do this, or I've never really had a need to do it. I want to update 1 sub category using Linq, so I can just write the whole category document using MongoDb as a ReplaceOneAsync(). But I just can't figure out how. This is in a .Net Core Controller.
{
"_id" : "5d9f97eb29d7b329209b13cb",
"Name" : "Solid State Drives",
"Description": "Great Drive",
"SubCategories" : [
{
"_id" : "5da8a1d7afb5d4084c80c9a4",
"Name" : "NVMe",
"Description" : "Fast Drive"
},
{
"_id" : "5da8a1d7afb5d4084c80c9a4",
"Name" : "2.5\" Form Factor",
"Description" : "Small Drive"
}
}I'm thinking this, but VS didn't like the left side.
var cR = GetCategory(cid);
cR.SubCategories.FirstOrDefault(sc => sc.Id == subCategory.Id) = subCategory;
UpdateCategory(cid, cR);I know I can do this, but I would like to preserve the original order.
cR.SubCategories.Remove(subCategory);
cR.SubCategories.Add(subCategory);Or this
var idx = -1;
foreach (var sc in cR.SubCategories)
{
idx++;
if (sc.Id.Equals(subCategory.Id))
{
cR.SubCategories[idx] = subCategory;
}
}I'm just looking for clean 1 liner to do this with if it exist.
If it ain't broke don't fix it Discover my world at jkirkerx.com
How about:
int index = cR.SubCategories.IndexOf(subCategory);
if (index == -1)
{
cR.SubCategories.Add(subCategory);
}
else
{
cR.SubCategories.RemoveAt(index);
cR.SubCategories.Insert(index, subCategory);
}Or:
int index = cR.SubCategories.IndexOf(subCategory);
if (index == -1)
{
cR.SubCategories.Add(subCategory);
}
else
{
cR.SubCategories[index] = subCategory;
}Unfortunately, to assign to the value returned from a method, you'd need a ref return[^]. And you can't do that with a
List<T>
, so you'd have to implement your own list class.
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
-
So this is really a MongoDb document class for a category, that has subCategories. Below is an example of how the data is structured. For some reason, I'm drawing a blank on how to do this, or I've never really had a need to do it. I want to update 1 sub category using Linq, so I can just write the whole category document using MongoDb as a ReplaceOneAsync(). But I just can't figure out how. This is in a .Net Core Controller.
{
"_id" : "5d9f97eb29d7b329209b13cb",
"Name" : "Solid State Drives",
"Description": "Great Drive",
"SubCategories" : [
{
"_id" : "5da8a1d7afb5d4084c80c9a4",
"Name" : "NVMe",
"Description" : "Fast Drive"
},
{
"_id" : "5da8a1d7afb5d4084c80c9a4",
"Name" : "2.5\" Form Factor",
"Description" : "Small Drive"
}
}I'm thinking this, but VS didn't like the left side.
var cR = GetCategory(cid);
cR.SubCategories.FirstOrDefault(sc => sc.Id == subCategory.Id) = subCategory;
UpdateCategory(cid, cR);I know I can do this, but I would like to preserve the original order.
cR.SubCategories.Remove(subCategory);
cR.SubCategories.Add(subCategory);Or this
var idx = -1;
foreach (var sc in cR.SubCategories)
{
idx++;
if (sc.Id.Equals(subCategory.Id))
{
cR.SubCategories[idx] = subCategory;
}
}I'm just looking for clean 1 liner to do this with if it exist.
If it ain't broke don't fix it Discover my world at jkirkerx.com
Just for fun, here's a simplistic - and not thoroughly tested! - example using ref returns:
public readonly struct SubCategory : IEquatable<SubCategory>
{
public SubCategory(int id, string name) => (Id, Name) = (id, name);
public int Id { get; }
public string Name { get; }
public override int GetHashCode() => Id;
public override bool Equals(object obj) => obj is SubCategory other && Equals(other);
public bool Equals(SubCategory other) => Id == other.Id;
}public class SubCategoryList : IEnumerable<SubCategory>
{
private SubCategory[] _categories = new SubCategory[4];
private int _length;public int Count => \_length; public int Capacity => \_categories.Length; public ref SubCategory this\[int index\] => ref \_categories\[index\]; public ref SubCategory FindOrAdd(int id) { for (int index = 0; index < \_length; index++) { if (\_categories\[index\].Id == id) { return ref \_categories\[index\]; } } Add(new SubCategory(id, null)); return ref \_categories\[\_length - 1\]; } public void Add(SubCategory value) { if (\_length == \_categories.Length) { int newSize = \_length \* 2; Array.Resize(ref \_categories, newSize); } \_categories\[\_length\] = value; \_length++; } public IEnumerator<SubCategory> GetEnumerator() { SubCategory\[\] categories = \_categories; int length = \_length; for (int index = 0; index < length; index++) { yield return categories\[index\]; } } IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
public class Category
{
public SubCategoryList SubCategories { get; } = new SubCategoryList();
}Usage:
var cR = new Category
{
SubCategories =
{
new SubCategory(1, "C1"),
new SubCategory(2, "C2"),
new SubCategory(3, "C3"),
}
};cR.SubCategories.FindOrAdd(2) = new SubCategory(2, "X2");
cR.SubCategories.FindOrAdd(42) = new SubCategory(42, "Z42");NB: I wouldn't recommend using this approach. :)
"These people looked deep within my soul and assigned me a number based on the
-
You can do
public class Jef { public int a; public int b; } public class Test { List list = new List(); private void test1() { list.First().b = 13; list.First(j => j.a == 12).b = 14; } }
when Jef is a class, as list.First() then returns the reference of a Jef object. And when null, it would throw a NullRefExc. You can't when Jef is a struct, as structs are value types, there is no reference or pointer to a value type. With structs the compiler rightfully gives the error: cannot modify the return value of ... because it is not a variable. Furthermore, I'm wondering what you expect from
FirstOrDefault
as a target for assignment: when no items match, the default would be what? where would the new value have to go? :)Luc Pattyn [My Articles] Nil Volentibus Arduum
On the
FirstOrDefault
, I know it's there because it's an update API. But now that you have my wheels turning, if multi-user and the sub category is deleted, then it fails. Category is a class.If it ain't broke don't fix it Discover my world at jkirkerx.com
-
Just for fun, here's a simplistic - and not thoroughly tested! - example using ref returns:
public readonly struct SubCategory : IEquatable<SubCategory>
{
public SubCategory(int id, string name) => (Id, Name) = (id, name);
public int Id { get; }
public string Name { get; }
public override int GetHashCode() => Id;
public override bool Equals(object obj) => obj is SubCategory other && Equals(other);
public bool Equals(SubCategory other) => Id == other.Id;
}public class SubCategoryList : IEnumerable<SubCategory>
{
private SubCategory[] _categories = new SubCategory[4];
private int _length;public int Count => \_length; public int Capacity => \_categories.Length; public ref SubCategory this\[int index\] => ref \_categories\[index\]; public ref SubCategory FindOrAdd(int id) { for (int index = 0; index < \_length; index++) { if (\_categories\[index\].Id == id) { return ref \_categories\[index\]; } } Add(new SubCategory(id, null)); return ref \_categories\[\_length - 1\]; } public void Add(SubCategory value) { if (\_length == \_categories.Length) { int newSize = \_length \* 2; Array.Resize(ref \_categories, newSize); } \_categories\[\_length\] = value; \_length++; } public IEnumerator<SubCategory> GetEnumerator() { SubCategory\[\] categories = \_categories; int length = \_length; for (int index = 0; index < length; index++) { yield return categories\[index\]; } } IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
public class Category
{
public SubCategoryList SubCategories { get; } = new SubCategoryList();
}Usage:
var cR = new Category
{
SubCategories =
{
new SubCategory(1, "C1"),
new SubCategory(2, "C2"),
new SubCategory(3, "C3"),
}
};cR.SubCategories.FindOrAdd(2) = new SubCategory(2, "X2");
cR.SubCategories.FindOrAdd(42) = new SubCategory(42, "Z42");NB: I wouldn't recommend using this approach. :)
"These people looked deep within my soul and assigned me a number based on the
Wow, that was an explosion of thought! I knew I could edit my class to help out, but it's been awhile since I've done it. This expands on Luc's thought in using struct and class. I've never used struct or have heard of it. But me going NoSQL, I can see where this is going to be a requirement for me to learn, now that I'm building a store and getting more complex with using data. I need time to adsorb this new info. Thanks Richard and Luc!
If it ain't broke don't fix it Discover my world at jkirkerx.com
-
So this is really a MongoDb document class for a category, that has subCategories. Below is an example of how the data is structured. For some reason, I'm drawing a blank on how to do this, or I've never really had a need to do it. I want to update 1 sub category using Linq, so I can just write the whole category document using MongoDb as a ReplaceOneAsync(). But I just can't figure out how. This is in a .Net Core Controller.
{
"_id" : "5d9f97eb29d7b329209b13cb",
"Name" : "Solid State Drives",
"Description": "Great Drive",
"SubCategories" : [
{
"_id" : "5da8a1d7afb5d4084c80c9a4",
"Name" : "NVMe",
"Description" : "Fast Drive"
},
{
"_id" : "5da8a1d7afb5d4084c80c9a4",
"Name" : "2.5\" Form Factor",
"Description" : "Small Drive"
}
}I'm thinking this, but VS didn't like the left side.
var cR = GetCategory(cid);
cR.SubCategories.FirstOrDefault(sc => sc.Id == subCategory.Id) = subCategory;
UpdateCategory(cid, cR);I know I can do this, but I would like to preserve the original order.
cR.SubCategories.Remove(subCategory);
cR.SubCategories.Add(subCategory);Or this
var idx = -1;
foreach (var sc in cR.SubCategories)
{
idx++;
if (sc.Id.Equals(subCategory.Id))
{
cR.SubCategories[idx] = subCategory;
}
}I'm just looking for clean 1 liner to do this with if it exist.
If it ain't broke don't fix it Discover my world at jkirkerx.com
So I was having trouble with my Angular Category program in which I would update a categories subCategory and it would add a subCategory or update the wrong one with remove and add, and IndexOf. So I pickup a Category Model in the API via HTTPGet and send it to Angular. Then I send just the SubCategory model within Category back to a different API via HTTPPut. In this API, I pick up the Category from MongoDB, then do
var index = category.SubCategories.IndexOf(subCategory);
and index returns -1. So I did a First to get the indexvar index = category.SubCategories.IndexOf(category.SubCategories.First(sc => sc.Id == subCategory.Id));
and I get 2 back which is correct. So in my other modules, I can pass a model to Angular, work on it and pass it back no problem. I suspect if I would of passed back the Category in whole the IndexOf(subCategory) would of worked. I'm just curious about this. Perhaps an explanation or knowledge will help create better designs.
If it ain't broke don't fix it Discover my world at jkirkerx.com