Entity Framework 6 AddOrUpdate is useless or what - c#

On the streak of my personal hell with the humongous EF (see last question), I decided to do some testing.
I did the most basic code first project I could think of with a local SQL Server database. I enabled migrations and it worked. Now to EF.
This is the most basic stuff I could think of trying to add a Parent property, with a list of children navigation properties.
DbContext
using System.Data.Entity;
namespace EFDBTest
{
public class MyDatabaseContext : DbContext
{
public DbSet<ParentClass> parents { get; set; }
public DbSet<ChildClass> children { get; set; }
}
}
Classes
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace EFDBTest
{
public class ParentClass
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
[Required]
[MaxLength(400)]
public string ParentDescription { get; set; }
//Should not be neeed as FK respects EF naming conventions
[ForeignKey("ParentClass_ID")]
public virtual List<ChildClass> Children { get; set; }
}
public class ChildClass
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
[Required]
[MaxLength(400)]
public string ChildrenDescription { get; set; }
[Required]
public int ParentClass_ID { get; set; }
}
}
And then some methods to test AddOrUpdate.
Insert methods seem to work correctly:
protected static bool createDataSetnormally()
{
try
{
ParentClass parent = new ParentClass()
{
ParentDescription = $"SOME RANDOM PARENT DESCRIPTNION NR: {random.Next(1, 10000000)}",
Children = new List<ChildClass>()
};
for (int i = 0; i < random.Next(2, 6); i++)
{
parent.Children.Add(new ChildClass() { ChildrenDescription = $"SOME RANDOM CHILDRE DESCRIPTNION NR: {random.Next(1, 10000000)}" });
}
using (var db = new MyDatabaseContext())
{
db.parents.Add(parent);
db.SaveChanges();
}
return true;
}
catch (Exception ex)
{
return false;
}
}
protected static bool createDataSetnormallyWithAttach()
{
try
{
using (var db = new MyDatabaseContext())
{
ParentClass parent = new ParentClass();
db.parents.Attach(parent);
parent.ParentDescription = $"SOME RANDOM PARENT DESCRIPTNION NR: {random.Next(1, 10000000)}";
parent.Children = new List<ChildClass>();
for (int i = 0; i < random.Next(2, 6); i++)
{
parent.Children.Add(new ChildClass() { ChildrenDescription = $"SOME RANDOM CHILDRE DESCRIPTNION NR: {random.Next(1, 10000000)}" });
}
db.parents.Add(parent);
db.SaveChanges();
}
return true;
}
catch (Exception ex)
{
return false;
}
}
protected static bool createDatasetAddOrUpdate()
{
try
{
ParentClass parent = new ParentClass()
{
ParentDescription = $"SOME RANDOM PARENT DESCRIPTNION NR: {random.Next(1, 10000000)}",
Children = new List<ChildClass>()
};
for (int i = 0; i < random.Next(2, 6); i++)
{
parent.Children.Add(new ChildClass() { ChildrenDescription = $"SOME RANDOM CHILDRE DESCRIPTNION NR: {random.Next(1, 10000000)}" });
}
using (var db = new MyDatabaseContext())
{
db.parents.AddOrUpdate(parent);
db.SaveChanges();
}
return true;
}
catch (Exception ex)
{
return false;
}
}
protected static bool createDatasetAddOrUpdateWithAttach()
{
try
{
using (var db = new MyDatabaseContext())
{
ParentClass parent = new ParentClass();
parent.ParentDescription = $"SOME RANDOM PARENT DESCRIPTNION NR: {random.Next(1, 10000000)}";
parent.Children = new List<ChildClass>();
for (int i = 0; i < random.Next(2, 6); i++)
{
parent.Children.Add(new ChildClass() { ChildrenDescription = $"SOME RANDOM CHILDRE DESCRIPTNION NR: {random.Next(1, 10000000)}" });
}
db.parents.AddOrUpdate(parent);
db.SaveChanges();
}
return true;
}
catch (Exception ex)
{
return false;
}
}
Update methods are a total mess. They insert double, triple, quadruple records, they don't update etc etc:
protected static bool updateDatasetAddOrUpdateOnlyParent(int IDparam)
{
try
{
ParentClass parent = new ParentClass()
{
ID = IDparam,
ParentDescription = $"SOME RANDOM PARENT DESCRIPTNION NR: 987654321",
Children = new List<ChildClass>()
};
using (var db = new MyDatabaseContext())
{
db.parents.AddOrUpdate(parent);
db.SaveChanges();
}
return true;
}
catch (Exception ex)
{
return false;
}
}
protected static bool updateDatasetAddOrUpdateParentAndChildren(int IDparam)
{
//NOT WORKING
try
{
using (var db = new MyDatabaseContext())
{
ParentClass parent = new ParentClass()
{
ID = IDparam,
ParentDescription = $"SOME RANDOM PARENT DESCRIPTNION NR: 123456789",
Children = new List<ChildClass>()
};
db.parents.Attach(parent);
for (int i = 0; i < random.Next(2, 6); i++)
{
parent.Children.Add(new ChildClass() { ID = 31, ChildrenDescription = $"SOME RANDOM CHILDRE DESCRIPTNION NR: 111111111", ParentClass_ID = IDparam });
parent.Children.Add(new ChildClass() { ID = 32, ChildrenDescription = $"SOME RANDOM CHILDRE DESCRIPTNION NR: 222222222", ParentClass_ID = IDparam });
parent.Children.Add(new ChildClass() { ChildrenDescription = $"SOME RANDOM CHILDRE DESCRIPTNION NR: 3333333333", ParentClass_ID = IDparam });
parent.Children.Add(new ChildClass() { ChildrenDescription = $"SOME RANDOM CHILDRE DESCRIPTNION NR: 44444444", ParentClass_ID = IDparam });
parent.Children.Add(new ChildClass() { ChildrenDescription = $"SOME RANDOM CHILDRE DESCRIPTNION NR: 555555555", ParentClass_ID = IDparam });
}
db.parents.AddOrUpdate(unique => unique.ParentDescription, parent);
db.SaveChanges();
}
return true;
}
catch (Exception ex)
{
return false;
}
}
protected static bool updateDatasetAddOrUpdateParentAndChildren2Steps(int IDparam)
{
try
{
ParentClass parent = new ParentClass()
{
ID = IDparam,
ParentDescription = $"SOME RANDOM PARENT DESCRIPTNION NR: 12223456789"
};
List<ChildClass> childrenToUpdate = new List<ChildClass>();
for (int i = 0; i < random.Next(2, 6); i++)
{
childrenToUpdate.Add(new ChildClass() { ID = 31, ChildrenDescription = $"SOME RANDOM CHILDRE DESCRIPTNION NR: 34343434", ParentClass_ID = IDparam });
childrenToUpdate.Add(new ChildClass() { ID = 32, ChildrenDescription = $"SOME RANDOM CHILDRE DESCRIPTNION NR: 3434343434", ParentClass_ID = IDparam });
childrenToUpdate.Add(new ChildClass() { ChildrenDescription = $"SOME RANDOM CHILDRE DESCRIPTNION NR: 22223332222222", ParentClass_ID = IDparam });
childrenToUpdate.Add(new ChildClass() { ChildrenDescription = $"SOME RANDOM CHILDRE DESCRIPTNION NR: 44423343242344444", ParentClass_ID = IDparam });
childrenToUpdate.Add(new ChildClass() { ChildrenDescription = $"SOME RANDOM CHILDRE DESCRIPTNION NR: 55234255552342342555", ParentClass_ID = IDparam });
}
using (var db = new MyDatabaseContext())
{
db.parents.AddOrUpdate(parent);
db.children.AddOrUpdate(c => c.ID, childrenToUpdate.ToArray());
db.SaveChanges();
}
return true;
}
catch (Exception ex)
{
return false;
}
}
What am I missing?
People here on SO says it's fault of the DB trying to generate identities, but I strongly doubt it has anything to do with that
EDIT:
IT BECAME EVEN MORE BUGGY: I relaunched today and it managed to create a NEW PARENT with id 10 even if I specify ID of parent is 9 as a parameter!!!!!!
Adding image showing table structure generated plus the various double records inserted:

Related

LINQ query to group parent and child elements

I'm currently working on a .NET 4.7 application. I need to create a tree structure out of unsorted data.
The final tree structure looks like this:
public class LocationViewModel
{
public int Id { get; set; }
public string Code { get; set; }
public List<LocationViewModel> ChildLocations { get; set; }
}
One Parent LocationViewModel can have several ChildLocations. Each ChildLocation can have several ChildLocations itself again.
I need to sort the data from the following structure. My unsorted data is a List<LinkParentChildViewModel> LinksParentChild, and looks like this:
public class LinkParentChildViewModel
{
public Location Parent { get; set; }
public LocationLink Child { get; set; }
}
public class Location
{
public int Id { get; set; }
public string Code { get; set; }
}
public class LocationLink
{
public int ParentLocationId { get; set; }
public int ChildLocationId { get; set; }
}
First I have a List<Location> Locations, which contains all the locations.
Then I'm getting a List<LinkParentChildViewModel> LinksParentChild, the entries are all mixed up - thus a Parent can be a child and a child can be a parent.
var LinksParentChild = new List<LinkParentChildViewModel>
{
new LinkParentChildViewModel
{
Parent = new Location
{
Id = 8,
Code = "ParLoc1",
},
Child = new LocationLink
{
ChildLocationId = 4,
ParentLocationId = null
}
},
new LinkParentChildViewModel
{
Parent = new Location
{
Id = 4,
Code = "Loc1",
},
Child = new LocationLink
{
ChildLocationId = 6,
ParentLocationId = 8
}
},
new LinkParentChildViewModel
{
Parent = new Location
{
Id = 6,
Code = "ChildLoc1",
},
Child = new LocationLink
{
ChildLocationId = null,
ParentLocationId = 4
}
},
new LinkParentChildViewModel
{
Parent = new Location
{
Id = 10,
Code = "LeftLoc1",
},
Child = new LocationLink
{
ChildLocationId = 11,
ParentLocationId = 4
}
},
new LinkParentChildViewModel
{
Parent = new Location
{
Id = 11,
Code = "LeftChildLoc1",
},
Child = new LocationLink
{
ChildLocationId = null,
ParentLocationId = 10
}
}
};
I need to write a LINQ query to group all nodes from my data into a List<LocationViewModel> result.
var result = LinksParentChild.GroupBy(x => x.Parent.Id).Select(x => new LocationViewModel
{
Id = x.First().Parent.Id,
Code = x.First().Parent.Code,
ChildLocations = new List<LocationViewModel>
{
// ... I'm stuck unfortunately, somehow i need to query and group all locations
}
}).ToList();
I tried, but unfortunately I'm stuck:
I need to select all Locations like a tree structure
Do you know how to solve this issue?
Thanks a lot!
The result looks like this:
var result = new List<LocationViewModel>
{
new LocationViewModel
{
Id = 8,
Code = "ParLoc1",
ChildLocations = new List<LocationViewModel>
{
new LocationViewModel
{
Id = 4,
Code = "Loc1",
ChildLocations = new List<LocationViewModel>
{
new LocationViewModel
{
Id = 6,
Code = "ChildLoc1"
},
new LocationViewModel
{
Id = 10,
Code = "LeftLoc1",
ChildLocations = new List<LocationViewModel>
{
new LocationViewModel
{
Id = 11,
Code = "LeftChildLoc1"
}
}
}
}
}
}
}
};
you can try with Recursion
public static List<LocationViewModel> GetHierarchy(List<LinkParentChildViewModel> linkParentChildViewModels, int parentId)
{
return linkParentChildViewModels.Where(x => x.Parent.Id == parentId).Select(x => new LocationViewModel
{
Id = x.Parent.Id,
Code = x.Parent.Code,
ChildLocations = GetHierarchy(linkParentChildViewModels, x.Child.ChildLocationId)
}).ToList();
}
Call this from Main method
var result = GetHierarchy(LinksParentChild, 8);

How to set up many to many relationship correctly with EF6?

I have some issues with getting my many to many relationship to work. I have two tables, Beestje and Accessoire, and I want to show its contents.
This are my tables:
Beestje:
public class Beestje
{
public Beestje()
{
this.Accessoires = new HashSet<Accessoire>();
}
[Key]
public int Id { get; set; }
public String Naam { get; set; }
public String Type { get; set; }
public int Prijs { get; set; }
public String Afbeelding { get; set; }
public virtual ICollection<Accessoire> Accessoires { get; set; }
}
Accessoire:
public class Accessoire
{
public Accessoire()
{
this.Beestjes = new HashSet<Beestje>();
}
[Key]
public int Id { get; set; }
public String Naam { get; set; }
public double Prijs { get; set; }
public String Afbeelding { get; set; }
public virtual ICollection<Beestje> Beestjes { get; set; }
}
In my controller I retrieve the contents from the Beestje table and return it to the view:
public ActionResult Beestjes()
{
ViewBag.Message = "Your application beestjes page";
List<Beestje> beestjes;
using (var context = new MyContext())
{
beestjes = context.Beestjes.ToList();
return View(beestjes);
}
}
When I print it like this there are no problems:
#model IEnumerable<BeestjeOpJeFeestje.Models.Beestje>
<h2>#ViewBag.Message</h2>
<ul>
#foreach (var a in Model)
{
<li>#a.Naam</li>
}
</ul>
But when I print it like this I get an error:
#model IEnumerable<BeestjeOpJeFeestje.Models.Beestje>
<h2>#ViewBag.Message</h2>
<ul>
#foreach (var a in Model)
{
<li>#a.Naam</li>
foreach (var b in a.Accessoires)
{
<li>#b.Naam</li>
}
}
</ul>
It goes wrong at the part where I call the a.Accessoires.
The error is:
"System.ObjectDisposedException: 'The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.'"
Does someone know the correct way, and would be willing to provide me the right code, or give me some directions?
Thanks in advance.
EDIT:
MyContext
public class MyContext : DbContext
{
public MyContext() : base("name=Local")
{
Database.SetInitializer(new MyContextInitializer());
}
public DbSet<Beestje> Beestjes { get; set; }
public DbSet<Accessoire> Accessoires { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
}
}
MyContextInitializer
public class MyContextInitializer : DropCreateDatabaseAlways<MyContext>
{
protected override void Seed(MyContext context)
{
base.Seed(context);
context.Beestjes.Add(new Beestje() { Id = 1, Naam = "Aap", Type = "Jungle", Prijs = 150, Afbeelding = "Content/images/aap.png" });
context.Beestjes.Add(new Beestje() { Id = 2, Naam = "Olifant", Type = "Jungle", Prijs = 250, Afbeelding = "Content/images/olifant.png" });
context.Beestjes.Add(new Beestje() { Id = 3, Naam = "Zebra", Type = "Jungle", Prijs = 200, Afbeelding = "Content/images/zebra.png" });
context.Beestjes.Add(new Beestje() { Id = 4, Naam = "Leeuw", Type = "Jungle", Prijs = 250, Afbeelding = "Content/images/leeuw.png" });
context.Beestjes.Add(new Beestje() { Id = 5, Naam = "Hond", Type = "Boerderij", Prijs = 75, Afbeelding = "Content/images/doggo.png" });
context.Beestjes.Add(new Beestje() { Id = 6, Naam = "Ezel", Type = "Boerderij", Prijs = 150, Afbeelding = "Content/images/donkey.png" });
context.Beestjes.Add(new Beestje() { Id = 7, Naam = "Koe", Type = "Boerderij", Prijs = 100, Afbeelding = "Content/images/koe.png" });
context.Beestjes.Add(new Beestje() { Id = 8, Naam = "Eend", Type = "Boerderij", Prijs = 50, Afbeelding = "Content/images/duck.png" });
context.Beestjes.Add(new Beestje() { Id = 9, Naam = "Kuiken", Type = "Jungle", Prijs = 35, Afbeelding = "Content/images/kuiken.png" });
context.Beestjes.Add(new Beestje() { Id = 10, Naam = "Pinguin", Type = "Sneeuw", Prijs = 175, Afbeelding = "Content/images/pingwing.png" });
context.Beestjes.Add(new Beestje() { Id = 11, Naam = "IJsbeer", Type = "Sneeuw", Prijs = 300, Afbeelding = "Content/images/ijsbeer.png" });
context.Beestjes.Add(new Beestje() { Id = 12, Naam = "Zeehond", Type = "Sneeuw", Prijs = 200, Afbeelding = "Content/images/zeehond.png" });
context.Beestjes.Add(new Beestje() { Id = 13, Naam = "Kameel", Type = "Woestijn", Prijs = 175, Afbeelding = "Content/images/kameel.png" });
context.Beestjes.Add(new Beestje() { Id = 14, Naam = "Slang", Type = "Sneeuw", Prijs = 125, Afbeelding = "Content/images/slang.png" });
var accessoire1 = new Accessoire() { Naam = "Banaan", Prijs = 0.50 };
accessoire1.Beestjes.Add(context.Beestjes.Find(1));
context.Accessoires.Add(accessoire1);
var accessoire2 = new Accessoire() { Naam = "Zadel", Prijs = 4.50 };
accessoire2.Beestjes.Add(context.Beestjes.Find(3));
context.Accessoires.Add(accessoire2);
var accessoire3 = new Accessoire() { Naam = "Krukje", Prijs = 5 };
accessoire3.Beestjes.Add(context.Beestjes.Find(4));
context.Accessoires.Add(accessoire3);
var accessoire4 = new Accessoire() { Naam = "Zweep", Prijs = 2.50 };
accessoire4.Beestjes.Add(context.Beestjes.Find(4));
context.Accessoires.Add(accessoire4);
var accessoire5 = new Accessoire() { Naam = "Bal", Prijs = 2.50 };
accessoire5.Beestjes.Add(context.Beestjes.Find(5));
accessoire5.Beestjes.Add(context.Beestjes.Find(12));
context.Accessoires.Add(accessoire5);
var accessoire6 = new Accessoire() { Naam = "Dansschoenen", Prijs = 3.00 };
accessoire6.Beestjes.Add(context.Beestjes.Find(10));
context.Accessoires.Add(accessoire6);
context.SaveChanges();
}
}
This is most likely caused by the fact that for each Beestje, the Accessoires property does not get loaded until you try to access it in the View, and at that moment the MyContext has already been disposed.
The solution is to tell EF to load them immediately by using .Include(), which is known as 'eager loading':
using (var context = new MyContext())
{
beestjes = context.Beestjes
.Include("Accessoires")
.ToList();
return View(beestjes);
}
For reference, see https://learn.microsoft.com/en-us/ef/ef6/querying/related-data

How To Convert IEnumerable To one object

In my Application Users can Have Multiple Roles , I Want To Convert List of Roles To One Common Role Object For Apply Permission
How i can handle convert List to Common role ?
public class Role
{
public boolData ListBools { get; set; }
public ListId ListIds { get; set; }
}
public class boolData
{
public bool CanSale { get; set; }
public bool CanBuy { get; set; }
}
public class ListId
{
public IEnumerable<Int64> Product { get; set; }
public IEnumerable<Int64> Formula { get; set; }
}
For Example this User have two Roles I Want to exucute common to one role object
IEnumerable<Role> UserRoles = new List<Role>()
{
new Role(){ListBools = new boolData()
{
CanBuy = false,
CanSale = true
},
ListIds = new ListId()
{
Product = new List<long>(){1,4,58},
Formula = new List<long>(){2,7,}
}
},
new Role(){ListBools = new boolData()
{
CanBuy = true,
CanSale = true
},
ListIds = new ListId()
{
Product = new List<long>(){1,6,70},
Formula = new List<long>(){2,9,}
}
},
};
must convert To
Role Result = new Role()
{
ListBools = new boolData()
{
CanBuy = true,
CanSale = true
},
ListIds = new ListId()
{
Product = new List<long>() { 1, 4, 6, 58, 70 },
Formula = new List<long>() { 2, 7, 9, }
}
};
You can use combination of Any and SelectMany() from Linq,
Like,
var Result = new Role()
{
ListBools = new boolData()
{
CanBuy = UserRoles.Any(x => x.ListBools.CanBuy),
CanSale = UserRoles.Any(x => x.ListBools.CanSale)
},
ListIds = new ListId()
{
Product = UserRoles.SelectMany(x => x.ListIds.Product).Distinct(),
Formula = UserRoles.SelectMany(x => x.ListIds.Formula).Distinct()
}
};
For list of Formulas and Products you can use SelectMany + Distinct:
Role sum = new Role
{
ListBools = new boolData()
{
CanBuy = true,
CanSale = true
},
ListIds = new ListId
{
Formula = UserRoles.SelectMany(x => x.ListIds.Formula).Distinct().ToList(),
Product = UserRoles.SelectMany(x => x.ListIds.Product).Distinct().ToList()
}
};
I'm not suer how ListBools should be produced .... Maybe you should group all rules and join Formula/Product per boolData
You could use this code:
SelectMany merges many Product/Formula lists into one
Distinct removes duplicates
OrderBy ensures a ascending order
Any checks if at least one CanBuy/CanSale property is true
Btw - I agree with the comments that say the Class/Property names could be be
var products = UserRoles.SelectMany(m => m.ListIds.Product).Distinct().OrderBy(m => m).ToList();
var formulas = UserRoles.SelectMany(m => m.ListIds.Formula).Distinct().OrderBy(m => m).ToList();
var anyCanBuy = UserRoles.Any(m => m.ListBools.CanBuy);
var anyCanSale = UserRoles.Any(m => m.ListBools.CanSale);
Role Result = new Role()
{
ListBools = new boolData()
{
CanBuy = anyCanBuy,
CanSale = anyCanSale,
},
ListIds = new ListId()
{
Product = products,
Formula = formulas,
}
};

Select n Items from the Child List?

how can I get N elements of the child list? Let's say I'd like to get 2 children for each parent.
public class Program
{
static void Main(string[] args)
{
var data = new List<Parent>()
{
new Parent()
{
Id = 1,
Name = "ParentName1",
Children = new List<Child>()
{
new Child() { Id = 1, Name = "ChildName1"},
new Child() { Id = 2, Name = "ChildName2"},
new Child() { Id = 3, Name = "ChildName3"},
new Child() { Id = 4, Name = "ChildName4"},
new Child() { Id = 5, Name = "ChildName5"},
}
},
new Parent()
{
Id = 2,
Name = "ParentName2",
Children = new List<Child>()
{
new Child() { Id = 6, Name = "ChildName6"},
new Child() { Id = 7, Name = "ChildName7"},
new Child() { Id = 8, Name = "ChildName8"},
new Child() { Id = 9, Name = "ChildName9"},
new Child() { Id = 10, Name = "ChildName10"},
}
}
};
// Get only 2 child elements for parent
var filteredData = data.Where(x => x.Children.Count >= 2)
.ToList();
foreach (var filteredParent in filteredData)
{
Console.WriteLine($"Parent {filteredParent.Id} with {filteredParent.Children.Count} children.");
}
Console.ReadKey();
}
}
public class Parent
{
public int Id { get; set; }
public string Name { get; set; }
public List<Child> Children { get; set; }
}
public class Child
{
public int Id { get; set; }
public string Name { get; set; }
public Parent Parent { get; set; }
}
One way to do it is to use a multi statement lambda expression for the result selector and List<T>'s RemoveRange method:
var query = data.Select
(
p =>
{
p.Children.RemoveRange(2, p.Children.Count - 2);
return p;
}
);
As Flater commented, It might be better to return a shallow copy of the parent, with only the first two children. That way your query does not change the source data:
var query = data.Select
(
p => new Parent()
{
Id = p.Id,
Name = p.Name,
Children = p.Children.Take(2).ToList()
}
);

List<class> how to get subtotal

What would be the simplest way to sum up all the TestScore that are the same SUBJECT and put the total value to each instance?
public class TestScore
{
public int ID { get; set; }
public int SUBJECT { get; set; }
public int SCORE { get; set; }
public int SUBTOTAL { get; set; }
}
List<TestScore> testScores = new List<TestScore>{
new TestScore{ ID = 0, SUBJECT = "MATH", SCORE = 10},
new TestScore{ ID = 1, SUBJECT = "MATH", SCORE = 20},
new TestScore{ ID = 2, SUBJECT = "ENGLISH", SCORE = 10},
new TestScore{ ID = 3, SUBJECT = "ENGLISH", SCORE = 20},
new TestScore{ ID = 4, SUBJECT = "ENGLISH", SCORE = 30},
};
Is there something like?
foreach (TestScore ts in testScores)
{
ts.SUBTOTAL = Sum(testScores.SUBJECT == ts.SUBJECT);
}
Provided that you declare a SUBJECT property in TestScores definition, this is what you need:
var grouped = testScores.GroupBy(ts=>ts.SUBJECT)
.Select(g => new {SUBJECT = g.Key,
Sum = g.Sum(ts=> ts.SCORE)});
The result will be an IEnumerable of an anonymous type, where each instance will have SUBJECT and Sum members.
testScores
.GroupBy(ts => ts.SUBJECT)
.Select(g => new {
Subject = g.Key,
Sum = g.Select(x => x.SCORE).Sum()
})
I think this might be what you are after.
public class TestScore
{
public int ID { get; set; }
public int TYPE { get; set; }
public int SCORE { get; set; }
public string SUBJECT { get; set; }
}
List<TestScore> testScores = new List<TestScore>{
new TestScore{ ID = 0, SUBJECT = "MATH", SCORE = 10},
new TestScore{ ID = 1, SUBJECT = "MATH", SCORE = 20},
new TestScore{ ID = 2, SUBJECT = "ENGLISH", SCORE = 10},
new TestScore{ ID = 3, SUBJECT = "ENGLISH", SCORE = 20},
new TestScore{ ID = 4, SUBJECT = "ENGLISH", SCORE = 30},
};
var tsList = from ts in testScores
group new {ts.SUBJECT,ts.SCORE} by ts.SUBJECT into grp
select new { Subject = grp.Key, Subtotal = grp.Sum(x => x.SCORE) };
foreach(var t in tsList)
Console.WriteLine("Subject: {0} - Subtotal: {1}", t.Subject, t.Subtotal);
Console.WriteLine("Press Any Key to Exit...");
Console.ReadKey();

Categories