Entity FrameWork many-to-many - asp.net-mvc-3

public class Project
{
public virtual int ID { get; set; }
[Required]
public virtual String Title { get; set; }
public String Definition { get; set; }
public DateTime StartDate { get; set; }
[Required]
public int CreaterID { get; set; }
public virtual ICollection<Status> Status { get; set; }
public virtual ICollection<Task> Tasks { get; set; }
public virtual ICollection<User> Users { get; set; }
public Project()
{
Users = new HashSet<User>();
}
}
public class User
{
public int ID { get; set; }
[DisplayName("Kullanıcı Adı")]
[Required]
[MinLength(5, ErrorMessage = "Kullanıcı Adı En Az 5 Karakter Olmalıdır")]
public string username { get; set; }
[DataType(DataType.Password)]
[DisplayName("Şifre")]
[Required]
[MinLength(3,ErrorMessage="Şifre En Az 3 Karakter Olmalıdır")]
public string password { get; set; }
[Required]
public String Name { get; set; }
[Required]
public String Surname { get; set; }
public int? CreaterID { get; set; }
public int level { get; set; }
public ICollection<Task> Tasks { get; set; }
public ICollection<Project> Projects { get; set; }
public User()
{
Projects = new HashSet<Project>();
}
}
public class TaskDB : DbContext
{
public DbSet<Comment> Comments { get; set; }
public DbSet<Project> Projects { get; set; }
public DbSet<Situation> Situaitons { get; set; }
public DbSet<Task> Tasks { get; set; }
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Project>().
HasMany(c => c.Users).
WithMany(p => p.Projects).
Map(
m =>
{
m.MapLeftKey("ProjectId");
m.MapRightKey("UserId");
m.ToTable("ProjectUser");
});
}
}
If I add project , current user added to project users list but project not added current user's projects list
This is my project add code
[HttpPost]
public ActionResult Create(Project proje,Status status)
{
proje.StartDate = DateTime.Now;
proje.Status = new HashSet<Status>();
var user = _db.Users.Single(r=> r.ID == UserRole.ID);
proje.Users.Add(user);
proje.Status.Add(status);
user.Projects.Add(proje);
if (ModelState.IsValid)
{
var projeler = _db.Projects;
projeler.Add(proje);
_db.SaveChanges();
return RedirectToAction("Index");
}
return View(proje);
}
I Search this problem's cause I did not find , I want to learn why entity framework add user to project's list but not add project to user's list

Your code to add the new project to the database looks correct and the relationship is most likely stored.
But possibly you don't load the Projects list with a User. If you call...
var project = _db.Projects.Single(p => p.ID == 1);
var users = project.Users; // lazy loading because Users is virtual
...you will see the project's users because they get lazily loaded since the Project.Users property is marked as virtual. If you do the same with a User...
var user = _db.Users.Single(u => u.ID == 1);
var projects = user.Projects; // no lazy loading because Projects is not virtual
...the projects don't get loaded because the User.Projects property is not marked as virtual.
Either mark the property as virtual as well to enable lazy loading for the User.Projects collection:
public virtual ICollection<Project> Projects { get; set; }
Or use eager loading:
var user = _db.Users.Include(u => u.Projects).Single(u => u.ID == 1);

Related

ef6 query many to many using bridge

how do I query this many to many relationship? I am starting with ACCOUNT, and want to return the ExecutingBroker.Firm associated with it.
I am starting with Account, then I guess drill to MANAGER, then to MAPPING_MANAGER, then to EXECUTINGBROKER.
Here is my query so far...
var student = dbEF.Accounts
.Where(x => x.AccountNumber == acctNum)
.Select(x => new DTOCrmDetails()
{
AccountNumber = x.AccountNumber,
AccountName = x.AccountName,
DateOpened = x.DateOpened,
CommissionId = x.CommissionId,
Commission = x.Commission,
ManagerID = x.ManagerID,
ManagerName = x.Manager.ManagerName,
Manager = x.Manager,
Employees = x.Manager.Employees,
WireInstructionsUSD = x.Manager.WireInstructionsUSDs
}).FirstOrDefault();
below is the code that was generated from ef from existing database.
public partial class Manager
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Manager()
{
this.Accounts = new HashSet<Account>();
this.Employees = new HashSet<Employee>();
this.WireInstructionsUSDs = new HashSet<WireInstructionsUSD>();
this.Mapping_ManagersExecutingBrokers = new HashSet<Mapping_ManagersExecutingBrokers>();
}
public int ManagerID { get; set; }
public string ManagerName { get; set; }
public string Strategy { get; set; }
public string ManagerShortCode { get; set; }
public Nullable<int> WireInstructionsUsdID { get; set; }
public Nullable<int> WireInstructionsForeignID { get; set; }
public string MEtradingPlatform { get; set; }
public string EtradingCostResp { get; set; }
public string NotesManager { get; set; }
public bool MainStrategy { get; set; }
public string PathPayments { get; set; }
public string PathEtrading { get; set; }
public string LEI { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Account> Accounts { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Employee> Employees { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<WireInstructionsUSD> WireInstructionsUSDs { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Mapping_ManagersExecutingBrokers> Mapping_ManagersExecutingBrokers { get; set; }
}
}
{
using System;
using System.Collections.Generic;
public partial class Mapping_ManagersExecutingBrokers
{
public int Mapping_ManagersExecutingBrokersId { get; set; }
public Nullable<int> ManagerID { get; set; }
public Nullable<int> ExecutingBrokersId { get; set; }
public virtual ExecutingBroker ExecutingBroker { get; set; }
public virtual Manager Manager { get; set; }
}
}
public partial class ExecutingBroker
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public ExecutingBroker()
{
this.Mapping_ManagersExecutingBrokers = new HashSet<Mapping_ManagersExecutingBrokers>();
}
public int ExecutingBrokersId { get; set; }
public string Firm { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<Mapping_ManagersExecutingBrokers> Mapping_ManagersExecutingBrokers { get; set; }
}
You have to go through Mapping_ManagersExecutingBrokers, since you've modelled it that way.
Keep in mind that you have a collection of Firms, since it's a many-to-many-relationship.
.Select(account => new { Firms = account.Manager.Mapping_ManagersExecutingBrokers
.Select(meb => meb.ExecutingBroker.Firm) });

Why is Entity Framework navigation property null?

I am use code first model with a relationship below
public class ApplicationUser : IdentityUser
{
public string UserFirstName { get; set; }
public string UserLastName { get; set; }
public string UserSchool { get; set; }
public UserProfileData UserProfileData { get; set; }
public int? MedicalSpecialtyId { get; set; }
public virtual MedicalSpecialty MedicalSpecialty { get; set; }
// public int? AnalyticsDataId { get; set; }
// public ICollection<AnalyticsData> AnalyticsDatas { get; set; }
}
public class MedicalSpecialty
{
public int Id { get; set; }
public string Description { get; set; }
// public int ApplicationUserId { get; set; }
public virtual ApplicationUser ApplicationUser { get; set; }
public ICollection<ProgramDetailData> ProgramDetailDatas { get; set; }
}
And when I try to get a User's associated MedicalSpecialty object it is NULL
userSpecialtyName = currentUser.MedicalSpecialty.Description;
BUT when I run this code above it the currentUser.MedicalSpecialty is no longer NULL. What happened?? Somehow that LINQ query woke up the object and filled it with data
var userSpecialtyId = currentUser.MedicalSpecialtyId;
userSpecialtyName = _medicalSpecialtyRepository.Find
(x => x.Id == userSpecialtyId).FirstOrDefault().Description;
userSpecialtyName = currentUser.MedicalSpecialty.Description;

The property is not a navigation property of entity type

I've designed my entities attached in the below diagram.
For this schema I would have written following query in sql to get all the roles, activities, applications for this user in the following way
select * from users u, roles r, userroles ur, roleappactivities raa, applications ap, activities ac
where u.Id = ur.UserId
and ur.RoleId = r.Id
and r.Id = raa.RoleId
and raa.ApplicationId = ap.Id
and raa.ActivityId = ac.Id
and u.id = 1
For the same to be achieved in my core application, I've written following code, which is failing. I ran out of ideas of how to achieve the above query through the following code. Any help much appreciated.
_context.Users
.Include("Roles")
.Include("RoleAppActivities")
.Include("Applications")
.Include("Activities")
.Where(x => x.Id == id)
.Select(x => new User
{
Id = x.Id,
TId = x.TId,
Roles = x.Roles
})
Edit:
Here are my entities
public class User
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public int Id { get; set; }
public string Name { get; set; }
public ICollection<UserRole> Roles { get; set; }
}
public class UserRole
{
public int UserId { get; set; }
public User User{ get; set; }
public int RoleId { get; set; }
public Role Role{get; set;}
}
public class Role
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public ICollection<UserRole> Users { get; set; }
public ICollection<RoleApplicationActivity> RoleApplicationActivity { get; set; }
}
public class RoleApplicationActivity
{
public int Id { get; set; }
public int RoleId { get; set; }
public int ApplicationId { get; set; }
public int ActivityId { get; set; }
public Activity Activity { get; set; }
public Application Application { get; set; }
public Role Role { get; set; }
}
public class Activity
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public int Id { get; set; }
public string Name { get; set; }
public ICollection<RoleApplicationActivity> RoleApplicationActivity { get; set; }
}
public class Application
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public int Id { get; set; }
public string Name { get; set; }
public ICollection<RoleApplicationActivity> RoleApplicationActivity { get; set; }
}
I think that your entity User should have the others collections (Roles ,
RoleAppActivities..). So you can directly load them by using .include(user=> user.Collection) , i think it is more strongly typed than using the .include("string)"..
I've to modify my query to following to fix the issue.
from u in _context.Users
from r in _context.Roles
from app in _context.Applications
from ac in _context.Activities
where u.Id == 1
select u

code first database model

I'm trying to create a MVC3 application, i'm troubled with EF code first to create DB.
I have this tables: User, Category, Product, Loan.
A User can create none or more Categories.
A User can add none or more Products.
A User can add none or more Loans.
A Category can have one or more Products.
A Category belongs to a User.
A Product can have none or more Loans.
A Product belongs to a User.
A Product is in a Category.
A Loan belongs to a User.
A Loan is added to a Product.
public class User
{
public int UserID { get; set; }
public string UserName { get; set; }
public virtual ICollection<Category> Categorys { get; set; }
public virtual ICollection<Product> Products { get; set; }
public virtual ICollection<Loan> Loans { get; set; }
}
public class Category
{
public int CategoryID { get; set; }
public string CategoryName { get; set; }
public int UserID { get; set; }
public virtual User User { get; set; }
public virtual ICollection<Product> Products { get; set; }
}
public class Product
{
public int ProductID { get; set; }
public string ProductName { get; set; }
public int UserID { get; set; }
public int CategoryID { get; set; }
public virtual User User { get; set; }
public virtual Category Category { get; set; }
public virtual ICollection<Loan> Loans { get; set; }
}
public class Loan
{
public int LoanID { get; set; }
public bool LoanStatus { get; set; }
public int UserID { get; set; }
public int ProductID { get; set; }
public virtual User User { get; set; }
public virtual Product Product { get; set; }
}
Have maded the context:
public class BuisnessContext : DbContext
{
public DbSet<User> Users { get; set; }
public DbSet<Category> Categorys { get; set; }
public DbSet<Product> Products { get; set; }
public DbSet<Loan> Loans { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
Have added the connectionString:
<add name="BuisnessContext"
connectionString="Data Source=|DataDirectory|Buisness.sdf"
providerName="System.Data.SqlServerCe.4.0"/>
Also a have maded a simple Initializer class:
public class BuisnessInitializer : DropCreateDatabaseIfModelChanges<BuisnessContext>
{
protected override void Seed(BuisnessContext context)
{
var users = new List<User>
{
new User { UserName = "u1"},
new User { UserName = "u2"} };
users.ForEach(s => context.Users.Add(s));
context.SaveChanges();
var categories = new List<Category>
{
new Category { CategoryName = "N1", UserID=1 } };
categories.ForEach(s => context.Categorys.Add(s));
context.SaveChanges();
var products = new List<Product>
{
new Product { ProductName = "N1", UserID = 1, CategoryID = 1 }
};
products.ForEach(s => context.Products.Add(s));
context.SaveChanges();
var loans = new List<Loan>
{
new Loan { LoanStatus = true, UserID = 2, ProductID = 1 }
};
loans.ForEach(s => context.Loans.Add(s));
context.SaveChanges();
}
}
Also i have generate a controller for User to get the users, but when i try to get the Users i received an error like:
Model compatibility cannot be checked because the EdmMetadata type was not included in the model. Ensure that IncludeMetadataConvention has been added to the DbModelBuilder conventions.
I tried to change the Database.SetInitializer<BuisnessContext>(new BuisnessInitializer());
whith Database.SetInitializer<BuisnessContext>(null);
Then i geted the error that table User doesen't exist and i didn't find any table in my APP_DATA folder -> Buisness.mdf
The database was created, but there was any table.
I understand that in my BuisnessContext i must to put some code for One to many or something like this, but i don't know how to do that.
Any help please!
I have found the answer for my question on .net mvc cyclical reference issue with entity
So the answer for me is like this:
modelBuilder.Entity<Product>()
.HasRequired(p => p.User).WithMany(p => p.Products).HasForeignKey(p => p.UserID).WillCascadeOnDelete(false);
modelBuilder.Entity<Product>()
.HasRequired(p => p.Category).WithMany(p => p.Products).HasForeignKey(p => p.CategoryID).WillCascadeOnDelete(false);
modelBuilder.Entity<Loan>()
.HasRequired(l => l.Product).WithMany(l => l.Loans).HasForeignKey(l => l.ProductID).WillCascadeOnDelete(false);
The reason is that here i am making some different path for the same tables like User - Category, User - Category - Product, Category - Product, User - Product - Loan.
Maybe it will be a good answer for others.

Multiple Parent models for a child model

I'm creating an MVC3 asp.net application using Entity Framework 4 and C#.
I've tried to read up on EF and model binding, lazy loading, etc. But I've hit an obstacle.
I have a User Model. The Store and UserType models can have an ICollection of Users. When I add a User with the Create Action, How do I specify multiple parents?
I think that I only know how to add if there is one parent.
My Models:
public class UserType
{
public virtual int ID { get; set; }
public virtual string UserTypeName { get; set; }
public virtual ICollection<User> Users { get; set; }
}
public class Store
{
public virtual int ID { get; set; }
public virtual string StoreName { get; set; }
public virtual Address StoreAddress { get; set; }
public virtual ICollection<Workroom> Workrooms { get; set;}
public virtual ICollection<User> Users { get; set; }
}
public class User
{
public virtual int ID { get; set; }
public virtual string Username { get; set; }
public virtual string Email { get; set; }
public virtual Store Store { get; set; }
public virtual UserType UserType { get; set; }
}
Here is my db context:
public DbSet<Workroom> Workrooms { get; set; }
public DbSet<Ticket> Tickets { get; set; }
public DbSet<Customer> Customers { get; set; }
public DbSet<Store> Stores { get; set; }
public DbSet<User> Users { get; set; }
public DbSet<UserType> UserTypes { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Store>()
.HasMany(store => store.Workrooms)
.WithRequired(workroom => workroom.Store);
modelBuilder.Entity<Store>()
.HasMany(store => store.Users)
.WithRequired(user => user.Store);
modelBuilder.Entity<UserType>()
.HasMany(usertype => usertype.Users)
.WithRequired(user => user.UserType);
base.OnModelCreating(modelBuilder);
}
Here's my create action:
public ActionResult Create()
{
return View(new User());
}
//
// POST: /Users/Create
[HttpPost]
public ActionResult Create(User newUser)
{
try
{
int storeID = newUser.Store.ID;
var store = _db.Stores.Single(r => r.ID == storeID);
store.Users.Add(newUser);
_db.SaveChanges();
return RedirectToAction("Index");
}
catch (Exception ex)
{
ModelState.AddModelError("", ex.InnerException.Message);
return View();
}
}
Do I just add another "Add" call for UserType? for example:
int userTypeID = newUser.UserType.ID
var usertype = _db.UserTypes.Single(s => s.ID == userTypeID)
How would the Entity Framework know that Users has another Parent??? ...do I care?
My hunch is that I should be doing this a different way, more specific and more accurate.
In this case, you probably want to add the user to the Users table, rather than the Stores. Then you assign the StoreID and UserTypeID to the user before you commit.
It looks like you're already setting the StoreID in your UI, are you doing the same for UserType? If so, then just add the user to the users table and you should be good.

Resources