I have the following models:
User:
public class User : IEntity, INamedType
{
public virtual int UserId { get; set; }
[Column(TypeName = "varchar")]
[StringLength(100)]
public virtual string UserName { get; set; }
[Column(TypeName = "varchar")]
[StringLength(100)]
public virtual string FirstName { get; set; }
[Column(TypeName = "varchar")]
[StringLength(100)]
public virtual string LastName { get; set; }
[Column(TypeName = "varchar")]
[StringLength(200)]
public virtual string EmailAddress { get; set; }
public int AreaId { get; set; }
[Column(TypeName = "varchar")]
[StringLength(64)]
public string CreatedByUserName { get; set; }
public DateTime CreatedDateTime { get; set; }
[Column(TypeName = "varchar")]
[StringLength(64)]
public string LastModifiedByUserName { get; set; }
public DateTime? LastModifiedDateTime { get; set; }
public bool Active { get; set; }
//Navigation properties
public virtual Area Area { get; set; }
public virtual ICollection<Role> Roles { get; set; }
}
Role:
public class Role : IEntity
{
public int RoleId { get; set; }
[Column(TypeName = "varchar")]
[StringLength(100)]
public string Name { get; set; }
[Column(TypeName = "varchar")]
[StringLength(1000)]
public string Description { get; set; }
[Column(TypeName = "varchar")]
[StringLength(64)]
public string CreatedByUserName { get; set; }
public DateTime CreatedDateTime { get; set; }
[Column(TypeName = "varchar")]
[StringLength(64)]
public string LastModifiedByUserName { get; set; }
public DateTime? LastModifiedDateTime { get; set; }
//Navigation Properties
public ICollection<User> Users { get; set; }
}
UserRole:
public class UserRole
{
public int UserId { get; set; }
public int RoleId { get; set; }
//Navigation properties
public virtual User User { get; set; }
public virtual Role Role { get; set; }
}
I also have a CustomRoleProvider with this method:
public override string[] GetRolesForUser(string username)
{
var user = _unitOfWork.UserRepository.GetUser(username);
var roles = from r in user.Roles
select r.Name;
if (roles != null)
return roles.ToArray();
else
return new string[] { };
}
so this all works fine until a an entry is added or removed from the UserRole table. For the User this record relates to the new Role when added by adding a UserRole row does not come through in the GetRolesForUser method. Likewise if a UserRole record is removed the Role keeps coming through for the record.
If however an IISReset occurs then all the correct records come through.
Anyone know why this would be happening and how to rectify?
The UserRole entity class conflicts with the join table created by EF for the many to many relationship.
You should either remove the UserRole entity or map the relationships in User and Role to the join entity
public class User : IEntity, INamedType
{
public virtual int UserId { get; set; }
public virtual ICollection<UserRole> Roles { get; set; }
}
public class Role : IEntity
{
public int RoleId { get; set; }
//Navigation Properties
public ICollection<UserRole> Users { get; set; }
}
Related
in my project (Asp.net Core Web Api) I have the tables "Truck" and "UserAccount with a one to many relashionship.
[Table("UserAccount")]
public class UserAccount : BaseClass
{
// Foreign Keys
[ForeignKey(nameof(UserAccountType))]
public int UserAccountTypeId { get; set; }
[ForeignKey(nameof(Gender))]
public int GenderId { get; set; }
[ForeignKey(nameof(Truck))]
public int TruckId { get; set; }
// Properties
public string LastName { get; set; }
public string FirstName { get; set; }
public string UserName { get; set; }
[DataType(DataType.EmailAddress)]
public string Mail { get; set; }
public string Login { get; set; }
[DataType(DataType.Password)]
public string Password { get; set; }
// Navigation Properties
[IgnoreDataMember]
public virtual Gender Gender { get; set; }
//public virtual Truck Truck { get; set; }
[IgnoreDataMember]
public virtual UserAccountType UserAccountType { get; set; }
public Truck Truck { get; set; }
}
[Table("Truck")]
public class Truck : BaseClass
{
// Foreign Keys
// Properties
[Column(Order = 3)]
public string Name { get; set; }
[DataType(DataType.EmailAddress)]
[Column(Order = 4)]
public string Mail { get; set; }
[Column(Order = 5)]
public string Phone { get; set; }
[Column(Order = 6)]
public string VATNumber { get; set; }
// Navigation Properties
public virtual ICollection<TruckFoodType> TruckFoodTypes { get; set; }
public virtual ICollection<TruckOption> TruckOptions { get; set; }
public ICollection<UserAccount> UserAccounts { get; set; }
}
In the method OnModelCreation into my ApplicationDbContex file I have this to create the one to many relashionship:
modelBuilder.Entity<UserAccount>()
.HasOne<Truck>(u => u.Truck)
.WithMany(t => t.UserAccounts)
.HasForeignKey(u => u.TruckId);
But when I try to populate the UserAccount table I have this error message :
"Merge instruction is in conflict with "FK_User_Account_TruckId". This conflict occurse in the database xxx table dbo.Truck column Id" (Sorry, Comes from a french translation)
I don't hunderstand why.
Can somebody help me?
Thanks
OK, stupid mistake. In some cases the TruckId field from the User Account table can be null. So I added a "?" to this fields like this : public int? TruckId { get; set; } Sorry for inconvenience
I have entities, service and view models. I use the service models in the services and in the service I map from entity to the service model and I return IQueryable<UserServiceModel> and I use the service in the controller but when I try to materialize the result and map it to the view model with Select it throw exception:
ArgumentException: Expression of type 'System.Collections.Generic.IAsyncEnumerable1[TestDriveServiceModel]' cannot be used for parameter of type 'System.Collections.Generic.IEnumerable1[TestDriveServiceModel]' of method 'System.Collections.Generic.List1[TestDriveServiceModel] ToList[TestDriveServiceModel](System.Collections.Generic.IEnumerable1[TestDriveServiceModel])'
Parameter name: arg0
// the service map from entities to service models and returns them
// userServiceModels is the result of the service
// Here the error is thrown
var viewModel = await userServiceModels.Select(usm => new UserViewModel()
{
TestDrivesCount = usm.TestDrives.Count()
}).ToListAsync();
public class UserServiceModel : IdentityUser
{
public string FirstName { get; set; }
public string LastName { get; set; }
public ICollection<TestDriveServiceModel> TestDrives { get; set; } = new List<TestDriveServiceModel>();
}
public class TestDriveServiceModel
{
public string Id { get; set; }
public string CarId { get; set; }
public CarServiceModel Car { get; set; }
public string UserId { get; set; }
public UserServiceModel User { get; set; }
public string StatusId { get; set; }
public StatusServiceModel Status { get; set; }
public DateTime ScheduleDate { get; set; }
public string Comment { get; set; }
}
public class User : IdentityUserEntity
{
public string FirstName { get; set; }
public string LastName { get; set; }
public ICollection<TestDriveEntity> TestDrives { get; set; } = new List<TestDriveEntity>();
}
public class TestDriveEntity
{
public string Id { get; set; }
[Required]
public string CarId { get; set; }
public BaseCarEntity Car { get; set; }
[Required]
public string UserId { get; set; }
public User UserEntity { get; set; }
[Required]
public string StatusId { get; set; }
public Status StatusEntity { get; set; }
[Required]
public DateTime ScheduleDate { get; set; }
public string Comment { get; set; }
}
My EF Code First model for some reason is not in sync with the db. I'm getting this error:
{"Invalid column name 'Type_Id1'."}
The field is actually called 'Type_Id' so I'm not sure from where that 1 comes up. I have the table column called as Type_Id and also I've added a Type_Id in my type entity model.
Why might I be getting that error message, plus why I'm getting 1 at the end of the name?
Update
My Task class:
public class Task
{
public Task()
{
Language = 1;
Grades = new HashSet<Grade>();
Categories = new HashSet<Category>();
Subjects = new HashSet<Subject>();
Rooms = new Collection<Room>();
Tools = new Collection<Tool>();
}
[Key]
public int Id { get; set; }
public string Description { get; set; }
public virtual TaskType Type { get; set; }
public string Rules { get; set; }
[Required]
[StringLength(200), MinLength(1)]
public string Name { get; set; }
public int PreperationTime { get; set; }
public int InstructionTime { get; set; }
public int TaskTime { get; set; }
public int Type_Id { get; set; }
public string VideoLink { get; set; }
[Required]
public int Language { get; set; }
public int? MinimumParticipants { get; set; }
public int? MaximumParticipants { get; set; }
public int? Rating { get; set; }
[Required]
public string CreatedBy { get; set; }
public virtual ICollection<Grade> Grades { get; set; }
public virtual ICollection<Category> Categories { get; set; }
public virtual ICollection<Subject> Subjects { get; set; }
public virtual ICollection<Room> Rooms { get; set; }
public virtual ICollection<Tool> Tools { get; set; }
}
DBContext class:
public ApplicationDbContext() : base("DefaultConnection", false)
{
}
public DbSet<Task> Tasks { get; set; }
public DbSet<TaskType> TaskTypes { get; set; }
public static ApplicationDbContext Create()
{
return new ApplicationDbContext();
}
You need to add the FK attribute on your navigation property. EF is creating Type_Id1 because Type_Id already exists (although it can't tell by convention it is the FK).
[ForeignKey("Type_Id")]
public virtual TaskType Type { get; set; }
https://msdn.microsoft.com/en-us/data/jj591583.aspx#Relationships
When creating many to many relationship using EF 4.3 code first approach, I cannot save data to connecting table, also cannot any examples on how to fill this table using saving object to Icollection... Here is my example:
MODELS
public class Hospital
{
//PK
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string County { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public Guid User_Id { get; set; }
//FK
public virtual ICollection<Operator> Operators { get; set; }
}
public class Operator
{
//PK
[Key]
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime Dob { get; set; }
public string Email { get; set; }
//FK
public virtual ICollection<Hospital> Hospitals { get; set; }
}
public class Project: DbContext
{
public DbSet<Hospital> Hospitals { get; set; }
public DbSet<Operator> Operators { get; set; }
}
CONTROLLER
public void AddOperater()
{
Hospital h = new Hospital();
h = db.Hospitals.Single(a=>a.Id ==1);
var o = new Operator();
o.FirstName = "John";
o.LastName = "Doe";
o.Dob = new DateTime(1988,2,12);
o.Email = "johndoe#gmail.com";
o.Hospitals.Add(h);
db.SaveChanges();
}
With this approach I keep getting error here: o.Hospitals.Add(h); even when my Hospital instance is filled with data. How exactly to save data to both tables, the dbo.Operators and dbo.OperatorHospital which is relationship table?
o.Hospitals.Add(h) will fail because the list is a null list. You cannot call Add() on a null list. Typically most people get around this by instantiating the list in the constructor of the entity... like so... the current line is blowing up due to a CSharp issue.
public class Hospital
{
//PK
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string County { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public Guid User_Id { get; set; }
//FK
public virtual ICollection<Operator> Operators { get; set; }
public Hospital()
{
Operators = new List<Operator>();
}
}
public class Operator
{
//PK
[Key]
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime Dob { get; set; }
public string Email { get; set; }
//FK
public virtual ICollection<Hospital> Hospitals { get; set; }
public Operator()
{
Hospitals = new List<Hospital>();
}
}
Hi I'm trying to set up my entity framework for a many to many relationship between User and Role.
The picture below shows what's in the database:
The Model for User is:
public class User : IEntity
{
public virtual int UserId { get; set; }
[Column(TypeName = "varchar")]
[StringLength(100)]
public virtual string UserName { get; set; }
[Column(TypeName = "varchar")]
[StringLength(100)]
public virtual string FirstName { get; set; }
[Column(TypeName = "varchar")]
[StringLength(100)]
public virtual string LastName { get; set; }
[Column(TypeName = "varchar")]
[StringLength(200)]
public virtual string EmailAddress { get; set; }
public int AreaId { get; set; }
[Column(TypeName = "varchar")]
[StringLength(64)]
public string CreatedByUserName { get; set; }
public DateTime CreatedDateTime { get; set; }
[Column(TypeName = "varchar")]
[StringLength(64)]
public string LastModifiedByUserName { get; set; }
public DateTime? LastModifiedDateTime { get; set; }
//Navigation properties
//public virtual Role Role { get; set; }
public virtual Area Area { get; set; }
public virtual ICollection<Role> Roles { get; set; }
}
Model for Role is:
public class Role : IEntity
{
public int RoleId { get; set; }
[Column(TypeName = "varchar")]
[StringLength(100)]
public string Name { get; set; }
[Column(TypeName = "varchar")]
[StringLength(1000)]
public string Description { get; set; }
[Column(TypeName = "varchar")]
[StringLength(64)]
public string CreatedByUserName { get; set; }
public DateTime CreatedDateTime { get; set; }
[Column(TypeName = "varchar")]
[StringLength(64)]
public string LastModifiedByUserName { get; set; }
public DateTime? LastModifiedDateTime { get; set; }
//Navigation Properties
public ICollection<User> Users { get; set; }
}
UserRole is:
public class UserRole
{
public int UserId { get; set; }
public int RoleId { get; set; }
//Navigation properties
public virtual User User { get; set; }
public virtual Role Role { get; set; }
}
So I thought I had this set up fine but in my code I go something like:
var roles = from r in user.Roles
select r.Name;
and it shoots itself giving errors of:
Server Error in '/' Application.
Invalid object name 'dbo.RoleUser'.
so I added the following to the context:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<User>()
.HasMany(i => i.Roles)
.WithMany(u => u.Users);
}
However now I'm getting errors of:
Server Error in '/' Application.
Invalid column name 'Role_RoleId'.
Invalid column name 'User_UserId'.
So surely I don't have something set up here correctly. Can andybody point me in the right direction?
You don't need to model the link table UserRole as a class since it has only the primary keys of the tables participate in the relationship. So remove the UserRole class.
If you are modeling an existing database, EF may infer the link table name to be RoleUser. To avoid this you can configure the link table as follows.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<User>()
.HasMany(i => i.Roles)
.WithMany(u => u.Users)
.Map(m =>
{
m.ToTable("UserRole");
m.MapLeftKey("UserId");
m.MapRightKey("RoleId");
});
}