Entity Framework : Filter nested collection by value of its properties - entity-framework

I have model as below
class MyClass()
{
public int Id { get; set; }
public List<Item> Items { get; set; }
}
class Item
{
public int Id { get; set; }
public string Name { get; set; }
}
both are added to DBContext as DbSets, now I would like to filter out the MyClass using the value of the Name property in the Items collection. How do I do this?

First of all correct your POCOs this way:
public class MyClass
{
public int Id { get; set; }
public virtual ICollection<Item> Items { get; set; }
}
public class Item
{
public int Id { get; set; }
public string Name { get; set; }
public virtual MyClass MyClass {get;set}
public int MyClassId {get;set}
}
Usage:
Presented query will return all MyClass instances, where at least one item's Name will satisfy condition:
var answer = db.MyClass.Where(c => c.Items.Any(item => item.Name == "Sam")).ToList();
This query will return all MyClass instances, where all item's Name will satisfy condition:
var answer = db.MyClass.Where(c => c.Items.All(item => item.Name == "Sam")).ToList();

Related

Insert in relationship table after inserting record

I have this classes and a WebApi method to POST the Item.
After inserting Item i want it to insert the inserted PK ItemId and given CategoryId into CategoryItem
public partial class Item
{
public int Id { get; set; }
public string? Name { get; set; }
public string? Description { get; set; }
public string? Type { get; set; }
}
public partial class Category
{
public int Id { get; set; }
public string? Description { get; set; }
public string? Name { get; set; }
}
public partial class Categoryitem
{
public int IdCategory { get; set; }
public int IdItem { get; set; }
public virtual Category IdCategoryNavigation { get; set; } = null!;
public virtual Item IdItemNavigation { get; set; } = null!;
}
[HttpPost]
public ActionResult<Item> PostItem(Item item)
{
_context.Item.Add(item);
_context.SaveChanges();
return Ok();
}
How do i pass the IdCategory into POST method ? Do I need a CategoryCollection in Item class and pass IdCategory through Item member ?
What about the relationship table ? How do i insert the two Ids ?
Thank you
you can create a viewmodel if you need to add several categories in the same time when you create an item, or if you only assign one category when you create an item you can just add CategoryId, but with attribute [NotMapped]
public partial class Item
{
public int Id { get; set; }
... another properties
[NotMapped]
public int? CategoryId{ get; set; }
}
or fluent api
modelBuilder.Entity<Item>().Ignore(c => c.CategoryId);
you will have to bind this CategoryId to dropdown list in the view
and action
[HttpPost]
public ActionResult<Item> PostItem(Item item)
{
var categoryitem = new Categoryitem
{
IdItemNavigation=item,
IdCategory = item.CategoryId
};
_context.Categoryitem.Add(categoryitem);
_context.SaveChanges();
return Ok(item);
}

Getting value of Navigation property in join

I have generated the classes from the database using scaffold.
public partial class Class1
{
public int ID { get; set; }
public int Class2ID { get; set; }
public string Name { get; set; }
public DateTime Address { get; set; }
public string City { get; set; }
public string Country { get; set; }
public virtual Class2 Class2 { get; set; }
}
public partial class Class2
{
public Class2()
{
Class1 = new HashSet<Class1>();
}
public int ID { get; set; }
public string Allotment { get; set; }
public string Manual { get; set; }
public virtual ICollection<Class1>Class1 {get; set;}
}
So there is a requirement to join these two tables in entity and get the data. And I am getting the result.
Here is my code:
var _class1Repo = UnitWork.GetGenericRepositoryFor<Class1>().AsNoTracking();
var _class2Repo = UnitWork.GetGenericRepositoryFor<Class2>().AsNoTracking();
var query = from _cls1 in _class1 in _class1Repo
join _cls2 in _class2Repo on _cls1.Class2ID = _cls2.ID
where _cls2.ID = 2
select new Class1() {
Name =_cls1 .Name,
Address =_cls1.Address,
City =_cls1 .City,
Country =_cls1.Country
// I want just only one property value inside this from class2
};
I need to include Class2 one property. How can I do that? Is there a way to achieve this?
Define your Class1.cs like this:
public class Class1
{
public int ID { get; set; }
public int Class2ID { get; set; }
public string Name { get; set; }
public DateTime Address { get; set; }
public string City { get; set; }
public string Country { get; set; }
public virtual Class2 Class2 { get; set; }
public Class1() {}
// Define this constructor
}
A constructor is a special method of the class which gets automatically invoked whenever an instance of the class is created.
So whenever you created instance you can easy to access the property.

How to map a table to an enumerable property using entity framework? (Database first)

Suppose I had these two classes:
public class MyClass {
public int Id { get; set; }
public IEnumerable<MyData> MyDataCollection { get; set; }
}
public class MyData {
public int DataId { get; set; }
public string Data { get; set; }
public int Id { get; set; }
}
and I had two tables in my database:
MyClasses:
Id
1
2
MyDatas:
DataId Id Data
1 - 1 - "Hello"
2 - 1 - "World"
3 - 2 - "Hello World"
How do I use entity framework to link them up, so that I can do:
using (var db = new DataContext()) {
var data = db.MyClass.Where(c => c.ID == 1).MyDataCollection;
foreach (var item in data) Console.WriteLine(item.Data);
}
I have the other data but so far I've just written [NotMapped] above the MyDataCollection property, but obviously I want to get rid of that and have it mapped. How do I (correctly) map it?
You can do it by expanding your class with appropriate navigation properties to establish the joins between them by following EF standards
public class MyClass {
public MyClass()
{
MyDataCollection = new List<MyData>();
}
public int Id { get; set; }
public virtual ICollection<MyData> MyDataCollection { get; set; }
}
public class MyData {
public int DataId { get; set; }
public string Data { get; set; }
public int Id { get; set; }
public virtual MyClass MyClass { get; set; }
}
Make sure these 2 entities are declared in the dbcontext as below
public class MyContext: DbContext
{
public MyContext(): base()
{
}
public DbSet<MyClass> MyClasses { get; set; }
public DbSet<MyData> MyDatas { get; set; }
}

Entity Framework 6 cast inheritance object when doing where clause

let' say i have a Comment table,
Admin and Member can Comment on it.
Admin and Member are inheritance from User,
so now i want to get comment and filter by a specific properties of member (groupName)
public class User
{
[Key]
public int id { get; set; }
public string name { get; set; }
public string type { get; set; } //member or admin
}
public class Admin : User
{
public string someProp { get; set; }
}
public class Member : User
{
public string groupName { get; set; }
}
public class Comment
{
[Key]
public int id { get; set; }
public string msg { get; set; }
[ForeignKey("user")]
public int user_id { get; set; }
public virtual User user { get; set; }
}
var comments = db.comments.Where(c => c.user.type == "member" && c.user.groupName == "abc").ToList();
of course above code can't working,
so any idea for me ?
Try this:
var comments = db.comments.Where(c =>
c.user is Member &&
(c.user as Member).groupName == "abc"
);
Also, if you'll expose the other end of the association (User -> Comments), it could be much easier:
public abstract class User
{
[Key]
public int id { get; set; }
public string name { get; set; }
public string type { get; set; } //member or admin
public virtual ICollection<Comment> Comments { get; set; }
}
Then:
var comments = db.users
.OfType<Member>()
.Where(x => x.groupName == "abc")
.SelectMany(x => x.Comments);
P.S I took the liberty to mark your User class as abstract.

NullReference error when adding a new model into a model property

I have the following entity framework code first models:
public class Member {
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string City { get; set; }
public String CardNumber { get; set; }
//Foreign Key
public virtual ICollection<Favorite> Favorites { get; set; }
[NotMapped]
public List<SelectListItem> FavoriteTypes { get; set; }
public Member() {
MembersDB db = new MembersDB();
FavoriteTypes = new List<SelectListItem>();
FavoriteTypes.AddRange(db.FavoriteTypes.ToList().Select(f => new SelectListItem { Text = f.Value, Value = f.ID.ToString() }));
}
}
public class FavoriteType {
public int ID { get; set; }
public string Value { get; set; }
}
public class Favorite {
public int ID { get; set; }
public String Value { get; set; }
//Foreign Keys
public virtual FavoriteType FavoriteType { get; set; }
public virtual Member Member { get; set; }
}
This creates a 1-M relationship for FavoriteTypes -> Favorites and 1-M relations for Member -> Favorites
Within my controller action, I retrieve most of the Member's info from Session saved at a couple pages back except for the favorites info which is gathered below. Then I gather the list of ID and input values to add to my new member as so:
[HttpPost]
public ActionResult AddFavs(List<int> ID, List<string> Value) {
MembersDB db = new MembersDB();
Member newMember = (Member)Session["member"];
if (ID != null && Value != null)
{
for (int i = 0; i < ID.Count(); i++)
{
int currentID = ID[i];
var test = new Favorite();
test.FavoriteType = db.FavoriteTypes.Where(f => f.ID == currentID).FirstOrDefault();
test.Value = Value[i];
newMember.Favorites.Add(test);
}
}
While running this code I get a NullReference error on this line newMember.Favorites.Add(test);
Not entirely sure why, any help would be appreciated.
EDIT: while troubleshooting in VS, the only null properties I can find are Favorites in newMember and Member in test
ICollection<Favorite> Favorites is null, so you can't add items to it. You should instantiate it in the constructor of your model:
public Member()
{
Favorites = new List<Favorite>();
// ...
}
Now it's an empty collection and you can add items to it.