EntityFramework code first keys - c#

I have following tables: User, UserGroups, and UserInGroups. You can see them on picture below. When i call User i want to be able to get Groups that user is in (UserInGroups). I am reading materials about EntityFramework but i am unable to make connections in code to to that, what am i missing? Do i need to connect them onModelCreating?
Currently i am not getting any data from UserInGroup or UserGroups.
DB looks like this
My classes look like this:
public class User : BaseEntity
{
public int RoleId { get; set; }
public Role Role { get; set; }
public UserGroup UserGroup { get; set; }
public UserInGroup UserInGroup { get; set; }
}
public class UserGroup : BaseEntity
{
public UserGroup()
{
Users = new List<User>();
UserInGroups = new List<UserInGroup>();
}
[StringLength(255)]
public string Name { get; set; }
public string KeyName { get; set; }
public List<User> Users { get; set; }
public List<UserInGroup> UserInGroups { get; set; }
}
public class UserInGroup : BaseEntity
{
public UserInGroup()
{
Users = new List<User>();
UserGroups = new List<UserGroup>();
}
public int UserId { get; set; }
public User User { get; set; }
public int UserGroupId { get; set; }
public UserGroup UserGroup { get; set; }
public List<User> Users { get; set; }
public List<UserGroup> UserGroups { get; set; }
}
DbContext:
public DbSet<GlobalSettings> GlobalSettings { get; set; }
public DbSet<Role> Roles { get; set; }
public DbSet<User> Users { get; set; }
public DbSet<UserGroup> UserGroups { get; set; }
public DbSet<UserInGroup> UsersInGroups { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<GlobalSettings>().Property(x => x.Key).HasColumnAnnotation("Index", new IndexAnnotation(new[] { new IndexAttribute("Index_VariablenName") { IsClustered = false, IsUnique = true } }));
}

public abstract partial class BaseEntity
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
}
public class User : BaseEntity
{
public string Username { get; set; }
public string Title { get; set; }
public FirstName { get; set; }
public string LasName { get; set; }
public Genders Gender { get; set; }
public string Email { get; set; }
public int RoleId { get; set; }
public string TechUser { get; set; }
public DateTime TechChangeDate { get; set; }
public int TechVersion { get; set; }
public bool IsDeleted { get; set; }
public virtual Role Role { get; set; }
public virtual ICollection<UserInGroup> UserInGroups { get; set; }
}
public class UserInGroup : BaseEntity
{
public int UserId { get; set; }
public int UserGroupId { get; set; }
public string TechUser { get; set; }
public DateTime TechChangeDate { get; set; }
public int TechVersion { get; set; }
public bool IsDeleted { get; set; }
public virtual User User { get; set; }
public virtual UserGroup UserGroup { get; set; }
}
public class UserGroup : BaseEntity
{
public string Name { get; set; }
public string KeyName { get; set; }
public string TechUser { get; set; }
public DateTime TechChangeDate { get; set; }
public int TechVersion { get; set; }
public bool IsDeleted { get; set; }
}
public class Role : BaseEntity
{
public string Name { get; set; }
}
public enum Genders
{
Male = 1,
Female = 2
}

You can use two methods to fill navigation properties. First is lazy-loading and second is explicit specifying of required properties.
For lazy-loading you should declare your navigation properties as virtual:
public class User : BaseEntity
{
public int RoleId { get; set; }
public virtual Role Role { get; set; }
public virtual UserGroup UserGroup { get; set; }
public virtual UserInGroup UserInGroup { get; set; }
}
public class UserGroup : BaseEntity
{
public UserGroup()
{
Users = new HashSet<User>(); // HashSet is more effective than List
UserInGroups = new HashSet<UserInGroup>();
}
[StringLength(255)]
public string Name { get; set; }
public string KeyName { get; set; }
public virtual ICollection<User> Users { get; set; } // ICollection is less restrective
public virtual ICollection<UserInGroup> UserInGroups { get; set; }
}
Now, you can load f.e. single user:
var justUser = dbContext.Users.Single(u => u.Id == 100);
When you need its properties they will by transparently loaded:
foreach (var userInGroup in user.UsersInGroups) // here is second loading
{
. . .
}
The second way is the calling of the Include method to explicit specifying required properties:
var userWithGroups = dbContext.Users
.Include(u => u.UserInGroups) // include single navigation property
.Include(ugs => ugs.Groups.Select(ug => ug.Group)) // include collection navigation property
.Single(u => u.Id == 100); // get the user with specified id and filled specified properties

Related

Entity Framework Core - Finding data in another table using a lambda function

I have two tables. Account and Tenant. There are many accounts to a tenant and this has been configured in the DbContext as follows.
modelBuilder.Entity<Account>()
.HasOne(b => b.Tenant)
.WithMany(a => a.Accounts)
.OnDelete(DeleteBehavior.Cascade);
The Account POCO class is as follows.
public class Account : IEntityBase, IAuditedEntityBase
{
public int Id { get; set; }
public int AccountNo { get; set; }
public string? AccountName { get; set; }
public string? Title { get; set; }
public string? AccountFirstName { get; set; }
public string? AccountLastName { get; set; }
public string? MobilePhone { get; set; }
public string? Email { get; set; }
public string? Address1 { get; set; }
public string? Address2 { get; set; }
public string? PasswordHash { get; set; }
public bool AcceptTerms { get; set; }
public int RoleId { get; set; }
public virtual Role Role { get; set; }
public string? VerificationToken { get; set; }
public DateTime? Verified { get; set; }
public bool IsVerified => Verified.HasValue || PasswordReset.HasValue;
public string? ResetToken { get; set; }
public DateTime? ResetTokenExpires { get; set; }
public DateTime? PasswordReset { get; set; }
public List<RefreshToken>? RefreshTokens { get; set; }
public bool OwnsToken(string token)
{
return this.RefreshTokens?.Find(x => x.Token == token) != null;
}
// One tenant to many user accounts
public int TenantId { get; set; }
public virtual Tenant? Tenant { get; set; }
// One suburb to many User accounts
public int SuburbId { get; set; }
public virtual Suburb? Suburb { get; set; }
}
The Tenant POCO class is as follows:
public class Tenant : IEntityBase, IAuditedEntityBase
{
public Tenant()
{
Accounts = new List<Account>();
}
public int Id { get; set; }
public int TenantNo { get; set; }
public string Database { get; set; }
public string CompanyName { get; set; }
public string ABN { get; set; }
public string CompanyAccountEmail { get; set; }
public string ContactFirstName { get; set; }
public string ContactLastName { get; set; }
public string OfficePhone { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string BankName { get; set; }
public string BankBSB { get; set; }
public string BankAccount { get; set; }
public int SuburbId { get; set; }
public virtual Suburb Suburb { get; set; }
// Many users to one tenant
public virtual ICollection<Account> Accounts { get; }
}
N ogiven there are multiple accounts to a tenant or "many accounts to one tenant" how,
if I have the account ID, obtain the tenantId using a lambda function.
I tried to use the following but got lost.
await tenantsContext.Accounts.Include(x => x.Tenant).Where(x => x.Id == accountId).SingleOrDefaultAsync(x => new Tenant.. and lost it here..
Can someone show me and others how you would, given an accountId (which equates to the Id of the account table) and get the TenantId for that account..
You can get TenantId for account with given accountId using this:
await tenantsContext.Accounts
.Where(x => x.Id == accountId)
.Select(x => x.TenantId)
.SingleOrDefaultAsync();

Automapper many to many mapping confusion

I have many to many relationship tables such as "User & Notification & UserNotification" and their entities, view models also.
There is only a difference between ViewModel and Entity classes. HasRead property is inside NotificationViewModel. How Can I map this entities to view models? I could not achieve this for HasRead property.
What I did so far is,
Mapping Configuration:
CreateMap<Notification, NotificationViewModel>();
CreateMap<User, UserViewModel>().ForMember(dest => dest.Notifications, map => map.MapFrom(src => src.UserNotification.Select(x => x.Notification)));
Notification class:
public class Notification : IEntityBase
{
public Notification()
{
this.UserNotification = new HashSet<UserNotification>();
}
public int Id { get; set; }
public string Header { get; set; }
public string Content { get; set; }
public System.DateTime CreateTime { get; set; }
public bool Status { get; set; }
public virtual ICollection<UserNotification> UserNotification { get; set; }
}
User Class
public class User : IEntityBase
{
public User()
{
this.UserNotification = new HashSet<UserNotification>();
}
public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public string Email { get; set; }
public string PhoneNumber { get; set; }
public bool Status { get; set; }
public virtual ICollection<UserNotification> UserNotification { get; set; }
}
UserNotification class:
public class UserNotification : IEntityBase
{
public int Id { get; set; }
public int UserId { get; set; }
public int NotificationId { get; set; }
public bool HasRead { get; set; }
public virtual Notification Notification { get; set; }
public virtual User User { get; set; }
}
UserViewModel class
public class UserViewModel : IValidatableObject
{
public int Id { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public string Email { get; set; }
public string PhoneNumber { get; set; }
public bool Status { get; set; }
public IList<NotificationViewModel> Notifications { get; set; }
}
NotificationViewModel class
public class NotificationViewModel
{
public int Id { get; set; }
public string Header { get; set; }
public string Content { get; set; }
public System.DateTime CreateTime { get; set; }
public bool Status { get; set; }
public bool HasRead { get; set; } // this is the difference
}
In order to fix up the HasRead, maybe you can utilize the AfterMap(Action<TSource, TDestination> afterFunction) function. It's not as elegant as the rest of automapper, but it might work.
CreateMap<User, UserViewModel>()
.ForMember(dest => dest.Notifications, map => map.MapFrom(src => src.UserNotification.Select(x => x.Notification)))
.AfterMap((src, dest) =>
{
foreach (var notificationVM in dest.Notifications)
{
notificationVM.HasRead = src.UserNotification.Where(x => x.NotificationId == notificationVM.Id).Select(x => x.HasRead).FirstOrDefault();
}
});

EF Code first not creating table with npgsql

I am using EF code first with Npgsql. Everything is fine till i try to save changes using contextclassObj
public class EmployeeRepository
{
private ESAppraisalcontext DBAccessObj = null;
public EmployeeRepository()
{
DBAccessObj = new ESAppraisalcontext();
DBAccessObj.Employees.Add(new Employee { EmployeeCode = "1", EmployeeName = "shuk" });
DBAccessObj.SaveChanges();
}
}
At the point SaveChanges() it gives an exception that the Relation \ ESTables.Employee\ doesnot exist.Here is my context class :
public class ESAppraisalcontext : DbContext
{
public DbSet<Entity> Entities { get; set; }
public DbSet<Employee> Employees { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.HasDefaultSchema("ESTables");
base.OnModelCreating(modelBuilder);
}
}
And my model:
public class Employee
{
[Key]
public string EmployeeCode { get; set; }
public string EmployeeName { get; set; }
public string EmailId { get; set; }
public string DomainName { get; set; }
public int DesignationId { get; set; }
public int DepartmentId { get; set; }
public string MgrCode { get; set; }
public int LocationId { get; set; }
public DateTime DOJ { get; set; }
public bool IsActive { get; set; }
public bool IsEligibleForCycle { get; set; }
public bool IsNonEligibleApprover { get; set; }
[ForeignKey("DepartmentId")]
public Departments department { get; set; }
[ForeignKey("DesignationId")]
public Designations designation { get; set; }
[ForeignKey("LocationId")]
public Locations Loation { get; set; }
}

add ICollection User in the same entity User

Whether it is possible so: it is a Messenger where the entity User content ICollection User that are collection Friends consist from the same Users?
If that possible please tell me how create a correct relationship between them in the DbContext file?
Or how better build this relationship. May be create separate entity?
Thanks in advance!
namespace Tinkl.Data.Core.Domain
{
public class User
{
public User()
{
Contacts = new List<User>();
Conversations = new List<Conversation>();
Invites = new List<User>();
}
public int UserId { get; set; }
public string NickName { get; set; }
public string EMail { get; set; }
public string Password { get; set; }
public DateTime? CreationDate { get; set; }
public DateTime? ExitDate { get; set; }
public string Picture { get; set; }
public string Status { get; set; }
public virtual ICollection<User> Invites { get; set; }
public virtual ICollection<User> Contacts { get; set; }
public virtual ICollection<Conversation> Conversations { get; set; }
}
}
You are going in right direction, see my below code same type of self-relationship in EF code first
public class ContentEntityRef : BaseModel
{
public ContentEntityRef()
{
RoleRefs = new HashSet<RoleRef>();
}
public int EntityId { get; set; }
public string EntityName { get; set; }
public int? ParentEntityId { get; set; }
public virtual ICollection<RoleRef> RoleRefs { get; set; }
public virtual ContentEntityRef Parent { get; set; }
public virtual ICollection<ContentEntityRef> Children { get; set; }
}
I had created seprate configuration file, you can same use in dbContext "OnModelCreating" method.
internal class ContentEntityRefConfiguration : EntityTypeConfiguration<ContentEntityRef>, IEntityConfiguration
{
public ContentEntityRefConfiguration()
{
this.HasKey(x => x.EntityId).Property(t => t.EntityId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
this.Property(x => x.EntityName).IsRequired().HasMaxLength(50);
this.HasMany(c => c.Children).WithOptional(c => c.Parent).HasForeignKey(c => c.ParentEntityId);
this.HasMany<RoleRef>(role => role.RoleRefs)
.WithMany(content => content.ContentEntities)
.Map(contentRole =>
{
contentRole.MapLeftKey("EntityID");
contentRole.MapRightKey("RoleID");
contentRole.ToTable("RoleEntityMap");
});
}
}
hope this will help you :)

How to fetch an attributes from my class with EF

I have 3 class, 2 are simple class and 1 combines the two of them.
public class Person:Base
{
public DateTime DOB { get; set; }
public string first { get; set; }
public string last { get; set; }
}
public class Roles:Base
{
public string Description { get; set; }
}
public class RolePerson:Base
{
public int pID { get; set; }
public virtual Person PersonID { get; set; }
public int rID { get; set; }
public virtual Roles RoleID { get; set; }
public int order { get; set; }
}
Now I have method that would select RolePerson witch would grab all member of pID with the id that i provide in the argument, and return the RoleID field.
this is how my method look like
public IEnumerable<Roles> PersonRoles(int personID)
{
return db.RolePerson.Where<RolePerson>((p) => p.pID == personID);
}
How can i say to return the role and not the roleperson.
Update:
My base class is as follow
public abstract class Base
{
public int ID { get; set; }
public Boolean isValid { get; set; }
public DateTime createdOn { get; set; }
public int createdID { get; set; }
public Person createdPerson { get; set; }
public DateTime updatedOn { get; set; }
public int updatedID { get; set; }
public Person updatedPerson { get; set; }
}
You can run a select statement in the end.
return d.RolePerson.Where(p => p.PId == personID).Select(r=> r.RoleID);

Categories