Entity framework join 2 tables - entity-framework

Beginner with entity framework and mvc here.
I have 2 table models:
UserProfile
[Table("UserProfile")]
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
}
and
ChatLogs
[Table("ChatLogs")]
public class ChatLogs
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int ChatLogId { get; set; }
[Column("Message")]
public string Message { get; set; }
[Column("UserId")]
public int UserId { get; set; }
public override string ToString()
{
return "Person: " + Message + " " + UserId;
}
}
UserId in table ChatLogs is foreign key to UserPorfile UserId primary key.
I am trying to join these 2 tables in Asp.NET MVC 4
Tested SQL query:
select * from UserProfile as a join ChatLogs as b on a.UserId = b.UserId
Tested Linq query:
from b in db.ChatLogs
select new {
ChatLogId = b.ChatLogId,
Message = b.Message,
UserId = b.UserId,
Column1 = (int?)b.UserProfile.UserId,
UserName = b.UserProfile.UserName,
Email = b.UserProfile.Email
}
I am using software called "Linqer" for learning purposes. It conversts SQL to Linq.
ActionResult code:
private ChatLogContext db = new ChatLogContext();
public ActionResult Index()
{
var list = from b in db.ChatLogs
select new
{
ChatLogId = b.ChatLogId,
Message = b.Message,
UserId = b.UserId,
Column1 = (int?)b.UserProfile.UserId,
UserName = b.UserProfile.UserName,
Email = b.UserProfile.Email
};
var vm = new ChatLogsViewModel { LogListString = string.Join("\n", list) };
return View(vm);
}
ChatLogViewModel has only a string variable for printing list in view.
But I get an error:
'Chat.Models.ChatLogs' does not contain a definition for 'UserProfile' and no extension method 'UserProfile' accepting a first argument of type 'Chat.Models.ChatLogs' could be found (are you missing a using directive or an assembly reference?)
So do I have to connect those 2 entities somehow so they would know about each other?

Try this:
[Table("UserProfile")]
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
**public virtual ICollection<ChatLogs> ChatLogs { get; set; }**
}
[Table("ChatLogs")]
public class ChatLogs
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int ChatLogId { get; set; }
[Column("Message")]
public string Message { get; set; }
[Column("UserId")]
public int UserId { get; set; }
**public virtual UserProfile UserProfile { get;set; }**
public override string ToString()
{
return "Person: " + Message + " " + UserId;
}
}

The easiest way to connect is to make Chatlogs available on the user as a List:
[Table("UserProfile")]
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
public List<ChatLog> ChatLogs{ get; set;}
}
Now you can do the following:
var users = Users.Include("ChatLogs");
Every user will now have its list of ChatLogs filled in correctly.

Related

How to include related table column names in dynamic linq expressions?

I am using a dynamic linq expressions to filter my records. All works well, if i give the column names which are there in the model. But when i try to give the column name in related table, it breaks. Can anyone please help here
Model
public class User
{
public int UserID { get; set; }
public string FirstName { get; set; } = string.Empty;
public string LastName { get; set; } = string.Empty;
public UserRole Role { get; set; }
public int RoleID { get; set; }
}
public class UserRole
{
public int RoleID { get; set; }
public string RoleName { get; set; } = String.Empty;
}
ParameterExpression param = Expression.Parameter(typeof(User), "t");
con = Expression.Equal(Expression.Property(param, "Role.RoleName"), Expression.Constant("Admin"));
var deleg = Expression.Lambda<Func<User, bool>>(con, param);
var users= context.UserModel.Include(r => r.Role).Where(deleg).AsQueryable();

Entity framework 6 use parentid in where clause with lambda expression

I'm new to EF and want to get an entry from my database (SQLite) in the following way:
Classes:
public class Customer
{
public Guid Id { get; set; }
public List<Month> Months { get; } = new List<Month>();
}
public class Month
{
public int Id { get; set; }
public string CacheId { get; set; }
public string Data { get; set; }
[Required]
public Customer Customer { get; set; }
}
DBContext:
public DbSet<Customer> Customers { get; set; }
public DbSet<Month> Months { get; set; }
Usage:
using (var context = new CustomerContext())
{
var customer = context.Customers.First();
context.Database.Log = Console.WriteLine;
var shouldContainOneEntry = context.Months.Where(x => x.Customer.Id == customer.Id).ToList();
}
shouldContainOneEntry is emtpy, but a test with a delegate and a static variable instead of the lambda expression worked:
private static Guid staticGuid;
public static bool DelegateTest(Month x)
{
return staticGuid == x.Customer.Id;
}
...
staticGuid = customer.Id;
var workingVersion = context.Months.Where(DelegateTest).ToList();
The generated SQL looks correct:
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[CacheId] AS [CacheId],
[Extent1].[Data] AS [Data],
[Extent1].[Customer_Id] AS [Customer_Id]
FROM [Months] AS [Extent1]
WHERE [Extent1].[Customer_Id] = #p__linq__0
-- p__linq__0: '5cfde6e0-5b3f-437b-84c8-2845b077462d' (Type = AnsiStringFixedLength, IsNullable = false)
Why is the version with the lambda expression not working?
The solution was found by following the hints of IvanStoev.
SQLite stores the Guid by default in a binary format.
Therefor a query like
SELECT * FROM Months WHERE CustomerId = '5cfde6e0-5b3f-437b-84c8-2845b077462d'
delivers an empty result.
Using SQLite Adminstrator the Guid is shown with the binary format.
Using the server explorer in VS the Guid is shown with a string format which lead me to the wrong conclusion that this should work.
After setting the option BinaryGUID of the connection string to false the code works fine.
Based on your declarations
public class Customer
{
public Guid Id { get; set; }
public List<Month> Months { get; } = new List<Month>();
}
public class Month
{
public int Id { get; set; }
public Guid CustomerId{get;set;} // you need to add the foreign Key of the customer ( i will suppose that your foreign key in db called CustomerId
public string CacheId { get; set; }
public string Data { get; set; }
[Required]
[ForeignKey("CustomerId")] // and you need to tell EF which column is the foreign key
public Customer Customer { get; set; }
}
how to use it now
using (var context = new CustomerContext())
{
var customer = context.Customers.First();
context.Database.Log = Console.WriteLine;
var shouldContainOneEntry = context.Months.Where(x => x.CustomerId == customer.Id).ToList();
}
hope it will help you

model passed to dictionary is of type .Data.Entity.Infrastructure.DbQuery , but it requires a model of type 'System.Collections.Generic.IEnumerable

What I am trying to do is
UserRoles:
public class UserRolesController : Controller
{
private HMSEntities db = new HMSEntities();
//
// GET: /UserRoles/
public ActionResult Index()
{
User user = (User)Session["User"];
var usr = db.Users.Find(user.Id);
ViewBag.Id = usr.Id;
ViewBag.FirstName = usr.FirstName;
if (Session["User"] != null)
{
var role = db.Roles.Where(u => u.Id == user.RoleId);
}
return View(usr);
}
Index.cshtml
#model IEnumerable<HMS.Models.User>
#using HMS.Models;
In this project when a user logs in then the user can view their details and then perform crud operations on roles of that user, but I am getting an error:
The model item passed into the dictionary is of type
'System.Data.Entity.Infrastructure.DbQuery1[HMS.Models.Role]', but
this dictionary requires a model item of type
'System.Collections.Generic.IEnumerable1[HMS.Models.User]'.
My Models are:
Role.cs
public partial class Role
{
public Role()
{
this.Users = new HashSet<User>();
}
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<User> Users { get; set; }
}
User.cs
public partial class User
{
public User()
{
this.Accesses = new HashSet<Access>();
this.Doctors = new HashSet<Doctor>();
this.Patients = new HashSet<Patient>();
this.Staffs = new HashSet<Staff>();
}
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public Nullable<System.DateTime> DOB { get; set; }
public Nullable<int> Age { get; set; }
public Nullable<int> PhoneNo { get; set; }
public Nullable<int> LandlineNO { get; set; }
public Nullable<bool> Status { get; set; }
public string PermentAddress { get; set; }
public string TemproryAddress { get; set; }
public string BloodGroup { get; set; }
public string Gender { get; set; }
public string EducationFinal { get; set; }
public string Experience { get; set; }
public string EmailId { get; set; }
public byte[] Image { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public Nullable<int> RoleId { get; set; }
public virtual ICollection<Access> Accesses { get; set; }
public virtual ICollection<Doctor> Doctors { get; set; }
public virtual ICollection<Patient> Patients { get; set; }
public virtual Role Role { get; set; }
public virtual ICollection<Staff> Staffs { get; set; }
}
I am new to mvc and don't know what else to do. If any further code is required please do tell and please reply.
db.Roles.Where(u => u.Id == user.RoleId);
Returns a DBQuery:
You have to convert it to List or Enumerable.
ViewBag.role = db.Roles.Where(u => u.Id == user.RoleId).AsEnumerable();
return View(ViewBag.role);
OR if you use List:
ViewBag.role = db.Roles.Where(u => u.Id == user.RoleId).ToList();
And you don't need to put in ViewBag:
var roles = db.Roles.Where(u => u.Id == user.RoleId).AsEnumerable();
return View(roles);
And in your View Change the Model from User to Roles:
#model IEnumerable<HMS.Models.User>
To Roles
#model IEnumerable<HMS.Models.Roles>
EDIT:
You are returning a Enumerable of Roles on this LINE: if (usr != null) return View(ViewBag.role); Not a User.
If you want to return the User and the Roles, you have to include the Roles in the User Model.
Something Like this in controller:
var usr = db.Users.Find(user.Id);
usr.Roles = db.Roles.Where(u => u.Id == user.RoleId).ToList();
return View(usr);
Then in the View:
#model HMS.Models.User
#foreach(var role in Model.Roles){
<p>#role.RoleId</p>
}

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.

how to (INSERT) data in this table in entity framework code first?

-------------------
using EF 6
-------------------
I have 3 table :
1) Users
public class Users
{
[Key,Required, MaxLength(50)]
public string UserName { get; set; }
[Required, MaxLength(128)]
public string Email { get; set; }
[Required, MaxLength(128)]
public string Password { get; set; }
}
2) Roles
public class Roles
{
[Key,Required, MaxLength(50)]
public string RoleName { get; set; }
[MaxLength(50)]
public string ApplicationName { get; set; }
}
3) UsersInRoles //My Problem.
public class UsersInRoles
{
[Key]
public int id { get; set; }
[ForeignKey("Users"), Required]
public string FKUserName { get; set; }
public virtual Users Users { get; set; }
[ForeignKey("Roles"), Required]
public string FKRoleName { get; set; }
public virtual Roles Roles { get; set; }
}
Now my question is how to insert record in UsersInRoles table ???
i use following code but don't insert any data in table!
even don't show any errors!
List<UsersInRoles> BUsersInRoles = new List<UsersInRoles>
{
new UsersInRoles { FKUserName="User1", FKRoleName="Role1"},
new UsersInRoles { FKUserName="User2", FKRoleName="Role2"}
};
foreach (UsersInRoles BIR in BUsersInRoles)
{
db.UsersInRoles.Add(BIR);
}
db.SaveChanges();
Thanks.
Update:
i have found a error :
The INSERT statement conflicted with the FOREIGN KEY constraint
"FK_dbo.UsersInRoles_dbo.Roles_FKRoleName". The conflict occurred in
database "AriyaRad", table "dbo.Roles", column 'RoleName'. The
statement has been terminated.
I solve my problem!
The reason was i define single string value for Foreign Key but try to insert list of string value!
db.UsersInRoles.Add(new UsersInRoles {FKUserName="User1",
FKRoleName="Role1", ApplicationName="PSCMS"});
db.SaveChanges();