Entity Framwork Update many to many - entity-framework

I am new to ef core. I am trying to implement many to many .
Here is my DBContext
public class MaxCiSDbContext : DbContext
{
public DbSet<Job> Jobs { get; set; }
public DbSet<Staff> Staffs { get; set; }
public MaxCiSDbContext(DbContextOptions<MaxCiSDbContext> options) : base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Job>()
.HasMany(t => t.Staffs)
.WithMany(t => t.Jobs);
base.OnModelCreating(modelBuilder);
}
}
and Here is my Staff Class
public class Staff
{
public string Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
public string Mobile { get; set; }
public string Address { get; set; }
//Navigation
public virtual ICollection<Job> Jobs { get; set; }
}
Here is my Job Class
public class Job
{
[Key]
public string Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string State { get; set; }
public string ClientOrderNumber { get; set; }
public string StartDate { get; set; }
public string DueDate { get; set; }
public string CompletedDate { get; set; }
public string ClientId { get; set; }
public string ManagerId { get; set; }
public string PartnerId { get; set; }
//Navigation
public virtual ICollection <Staff> Staffs { get; set; }
}
I Call an API which returns a XmlDocument, I read that document and update database.
Here is how I deal with xmldocument.
//Fetch Current Jobs and populate to DB
XmlDocument apiresults = JobMethods.GetCurrent();
XmlNodeList nodes = apiresults.DocumentElement.SelectNodes("/Response/Jobs/Job");
foreach (XmlNode node in nodes)
{
Job MaxCiSJob = new Job()
{
Id = node.SelectSingleNode("ID").InnerText,
Name = node.SelectSingleNode("Name").InnerText,
Description = node.SelectSingleNode("Description").InnerText,
State = node.SelectSingleNode("State").InnerText,
ClientOrderNumber = node.SelectSingleNode("ClientOrderNumber").InnerText,
StartDate = node.SelectSingleNode("StartDate").InnerText,
DueDate = node.SelectSingleNode("DueDate") != null ? node.SelectSingleNode("DueDate").InnerText : "",
CompletedDate = node.SelectSingleNode("CompletedDate") != null ? node.SelectSingleNode("CompletedDate").InnerText : "",
ClientId = node.SelectSingleNode("Client/ID").InnerText,
ManagerId = node.SelectSingleNode("Manager/ID") != null ? node.SelectSingleNode("Manager/ID").InnerText : "",
PartnerId = node.SelectSingleNode("Partner") != null ? node.SelectSingleNode("Partner").InnerText : ""
};
XmlNodeList Assigned = node.SelectNodes("Assigned/Staff");
MaxCiSJob.Staffs = new Collection<Staff>();
foreach (XmlNode staffNode in Assigned)
{
var staffId = staffNode.SelectSingleNode("ID").InnerText;
var staff = _db.Staffs.Find(staffId);
if(staff != null)
{
MaxCiSJob.Staffs.Add(staff);
}
}
if (_db.Jobs.Find(MaxCiSJob.Id) == null)
{
//Insert Record
_db.Jobs.Add(MaxCiSJob);
}
else
{
// UPDATE recorde
_db.Jobs.Update(MaxCiSJob);
}
}
_db.SaveChanges();
}
Everything works well when I run the program for the first time(The linking table ,"JobStaff", is empty) but when I run the Program for the second time I get an excetpion:
SqlException: Violation of PRIMARY KEY constraint 'PK_JobStaff'. Cannot insert duplicate key in object 'dbo.JobStaff'. The duplicate key value is (J14995, 557898).
Can someone please help me on how can I resolve this issue.

Running your code EF core wants to add entities anyway. Because your entities are not attached.
Try this code:
//Fetch Current Jobs and populate to DB
XmlDocument apiresults = JobMethods.GetCurrent();
XmlNodeList nodes = apiresults.DocumentElement.SelectNodes("/Response/Jobs/Job");
foreach (XmlNode node in nodes)
{
var id = node.SelectSingleNode("ID").InnerText;
Job MaxCiSJob = _db.Jobs.Find(id);
if (MaxCiSJob == null)
{
MaxCiSJob = new Job() { Id = id };
_db.Jobs.Add(MaxCiSJob);
}
MaxCiSJob.Name = node.SelectSingleNode("Name").InnerText;
MaxCiSJob.Description = node.SelectSingleNode("Description").InnerText;
MaxCiSJob.State = node.SelectSingleNode("State").InnerText;
MaxCiSJob.ClientOrderNumber = node.SelectSingleNode("ClientOrderNumber").InnerText;
MaxCiSJob.StartDate = node.SelectSingleNode("StartDate").InnerText;
MaxCiSJob.DueDate = node.SelectSingleNode("DueDate") != null ? node.SelectSingleNode("DueDate").InnerText : "";
MaxCiSJob.CompletedDate = node.SelectSingleNode("CompletedDate") != null ? node.SelectSingleNode("CompletedDate").InnerText : "";
MaxCiSJob.ClientId = node.SelectSingleNode("Client/ID").InnerText;
MaxCiSJob.ManagerId = node.SelectSingleNode("Manager/ID") != null ? node.SelectSingleNode("Manager/ID").InnerText : "";
MaxCiSJob.PartnerId = node.SelectSingleNode("Partner") != null ? node.SelectSingleNode("Partner").InnerText : "";
XmlNodeList Assigned = node.SelectNodes("Assigned/Staff");
foreach (XmlNode staffNode in Assigned)
{
MaxCiSJob.Staffs.Clear();
var staffId = staffNode.SelectSingleNode("ID").InnerText;
var staff = _db.Staffs.Find(staffId);
if (staff != null)
{
MaxCiSJob.Staffs.Add(staff);
}
}
}
_db.SaveChanges();
And you should change your domains this way in order not to get NullReferenceException:
public class Staff
{
public string Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
public string Mobile { get; set; }
public string Address { get; set; }
//Navigation
public virtual ICollection<Job> Jobs { get; set; } = new Collection<Job>();
}
public class Job
{
[Key]
public string Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string State { get; set; }
public string ClientOrderNumber { get; set; }
public string StartDate { get; set; }
public string DueDate { get; set; }
public string CompletedDate { get; set; }
public string ClientId { get; set; }
public string ManagerId { get; set; }
public string PartnerId { get; set; }
//Navigation
public virtual ICollection<Staff> Staffs { get; set; } = new Collection<Staff>();
}

Related

Could not find the implementation of the query pattern for source type. Join not found

I don't know if I am doing this right. I have 2 tables Property and PropertyTypes. Each Property has 1 PropertyType. I am using a foreign key constraint. But on the creation of the controller, I get this error already:
"Could not find an implementation of the query pattern for source type 'DbSet'.'Join not found'
Please see my code below:
[Table("Property.Property")]
public class Property
{
[Key]
public int PropertyId { get; set; }
[StringLength(50)]
public string PropertyName { get; set; }
public int? Owner { get; set; }
public string Cluster { get; set; }
public string PropertyNumber { get; set; }
public string RegionCode { get; set; }
public string ProvinceCode { get; set; }
public string MunicipalCode { get; set; }
public string BarangayCode { get; set; }
public DateTime? DateAdded { get; set; }
public DateTime? DateModified { get; set; }
public int PropertyTypeId { get; set; }
public PropertyType PropertyType { get; set; }
[NotMapped]
public string Type { get; set; }
}
[Table("Property.Types")]
public class PropertyType
{
[Key]
public int PropertyTypeId { get; set; }
[StringLength(50)]
public string Type { get; set; }
public DateTime? DateAdded { get; set; }
public DateTime? DateModified { get; set; }
public List<Property> Properties { get; set; }
}
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false) {}
// DB Sets
public DbSet<Property> Properties { get; set; }
public DbSet<PropertyType> PropertyTypes { get; set; }
}
Controller
public class PropertyController : ApiController
{
[HttpGet]
[Authorize]
[Route("api/getproperties")]
public async Task<List<Property>> GetProperties()
{
using(var db = new ApplicationDbContext())
{
var properties = await (from p in db.Properties
join pt in db.PropertyTypes
on p.PropertyTypeId equals pt.PropertyTypeId
select new
{
PropertyId = p.PropertyId,
PropertyName = p.PropertyName,
Owner = p.ProertyOwner,
Cluster = p.Cluster,
PropertyNumber = p.PropertyNumber,
RegionCode = p.RegionCode,
ProvinceCode = p.ProvinceCode,
MunicipalCode = p.MunicipalCode,
BarangayCode = p.BarangayCode,
DateAdded = p.DateAdded,
DateModified = p.DateModified,
PropertyTypeId = p.PropertyTypeId,
type = pt.Type
}
).ToListAsync();
return properties;
}
}
}
Can you please show me the right way to do this? Thank you.

Entity Framework Include error

I have the following Model objects
public class UserEntry
{
public int UserEntryID { get; set; }
public string UserID { get; set; }
public string TeamName { get; set; }
public int Total { get; set; }
public virtual ICollection<EntryPlayer> EntryPlayers { get; set; }
}
public class EntryPlayer
{
public int EntryPlayerID { get; set; }
public bool Captain { get; set; }
public virtual int UserEntryID { get; set; }
public virtual Player Player { get; set; }
}
public class Player
{
public int PlayerID { get; set; }
public string FirstName { get; set; }
public string MiddleInitial { get; set; }
public string LastName { get; set; }
public int Group { get; set; }
public string Team { get; set; }
public int Score { get; set; }
}
My database schema looks like this:-
When I try and load a UserEntry using this code:-
UserEntry userEntry = this.db.UserEntries
.Where(u => u.UserID == user.Id)
.Include("EntryPlayers")
.FirstOrDefault();
I get the error:
Invalid column name 'Player_PlayerID'
If I change the Player property on my UserEntry object from:
public virtual Player Player { get; set; }
to:
public virtual int PlayerID { get; set; }
then my UserEntry object loads fine but obviously only has the PlayerID and not the whole Player object in it.
What do I need to change so that I can load the Player object within the UserEntry?
I also have this DatabaseInitializer class
namespace ACS.Models {
public class ACSDatabaseInitializer : CreateDatabaseIfNotExists<ACSContext>
{
protected override void Seed(ACSContext context)
{
base.Seed(context);
var players = new List<Player>();
players.Add(new Player
{
PlayerID = 1,
FirstName = "Dave",
MiddleInitial = "",
LastName = "Smith",
Group = 1,
Team = "Team1",
Score = 0
});
players.ForEach(p => context.Players.Add(p));
context.SaveChanges();
}
}
}
and this Context class
namespace ACS.Models
{
public class ACSContext : DbContext
{
public ACSContext()
: base("name=ACS")
{
Database.SetInitializer<ACSContext>(null);
}
public DbSet<Player> Players { get; set; }
public DbSet<UserEntry> UserEntries { get; set; }
public DbSet<EntryPlayer> EntryPlayers { get; set; }
}
}
I needed both a PlayerID property and a Player property on my UserEntry object for this to work

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>
}

Update only a single column using EF5 in MVC4

I have an UserProfile model
public class UserProfile
{
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
[Key]
[Required]
public string EmailAddress { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string Surname { get; set; }
[Required]
public string BusinessUnit { get; set; }
[Required]
public string JobRole { get; set; }
public bool IsEnabled { get; set; }
public string Password { get; set; }
}
I want to update only the password field.
This is the code I am trying
if (ModelState.IsValid)
{
var context = new JhaDbContext();
using (JhaDbContext jdc = new JhaDbContext())
{
try
{
jdc.UserProfiles.Attach(userProfile);
userProfile.Password = model.NewPassword;
jdc.SaveChanges();
httpStatus = HttpStatusCode.OK;
}
catch (InvalidOperationException ioe)
{
httpStatus = HttpStatusCode.BadRequest;
}
catch (DbEntityValidationException ev)
{
httpStatus = HttpStatusCode.BadRequest;
}
}
}
I get the DbEntityValidationException on the required fields. Please guide me in solving this.
Regards
Sudheep
I usually would do a
var myEntity = jdc.(tableName).find(userID);
then set
myEntity.Password = "new password";
jdc.Entry(userProfile).State = System.Data.EntityState.Modified;
/* why do you have it as unchanged? */
jdc.saveChanges()

EF code first property not mapped

The problem I'm encountering is when I try to insert a new record in a ASPxGridView which is a master of detail in an asp.net page.
This only occurs when adding a new record is required when there is no record.
EnderecoEscola entity:
namespace DAL
{
[Table("CAD_ENDERECO_ESCOLA")]
public class EnderecoEscola
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ENDESC_ID { get; set; }
[Required]
public int ESCOLA_ID { get; set; }
[Association("Escolas", "ESCOLA_ID", "ESCOLA_ID")]
[ForeignKey("ESCOLA_ID")]
public virtual Escola Escola { get; set; }
[Required]
public int TPOEND_ID { get; set; }
[ForeignKey("TPOEND_ID")]
public virtual TipoEndereco TipoEndereco { get; set; }
[Required]
public int ENDESC_UF_ID { get; set; }
[ForeignKey("ENDESC_UF_ID")]
public virtual UnidadeFederativa UnidadeFederativa { get; set; }
[Required]
public int ENDESC_MUN_iD { get; set; }
[ForeignKey("ENDESC_MUN_iD")]
public virtual Municipio Municipio { get; set; }
[StringLength(10), Required]
[MinLength(8)]
public string ENDESC_CEP { get; set; }
[StringLength(100), Required]
[MinLength(10)]
public string ENDESC_ENDERECO { get; set; }
[StringLength(15)]
public string ENDESC_NRO { get; set; }
[StringLength(25)]
public string ENDESC_COMPL { get; set; }
[StringLength(70)]
public string ENDESC_BAIRRO { get; set; }
[NotMapped]
public String TPEND_DESCRICAO { get; set; }
[NotMapped]
public String UF_SIGLA { get; set; }
[NotMapped]
public String MUN_DESCRICAO { get; set; }
}
}
DAL :
namespace DAL.utilities
{
public class OperationCadEnderecoEscola
{
public IQueryable<EnderecoEscola> GetId(int idEsc)
{
using (SecurityCtx ctx = new SecurityCtx())
{
ctx.Configuration.LazyLoadingEnabled = false;
var query = ctx.EnderecoEscola.Include("TipoEndereco").Include("UnidadeFederativa").Include("Municipio").Where(w => w.ESCOLA_ID == idEsc).OrderBy(p => p.ENDESC_ENDERECO).ToList().
Select(w => new EnderecoEscola
{
ENDESC_ID = w.ENDESC_ID,
ESCOLA_ID = w.ESCOLA_ID,
TPOEND_ID = w.TPOEND_ID,
ENDESC_UF_ID = w.ENDESC_UF_ID,
ENDESC_MUN_iD = w.ENDESC_MUN_iD,
ENDESC_CEP = w.ENDESC_CEP,
ENDESC_ENDERECO = w.ENDESC_ENDERECO,
ENDESC_NRO = w.ENDESC_NRO,
ENDESC_COMPL = w.ENDESC_COMPL,
ENDESC_BAIRRO = w.ENDESC_BAIRRO,
TPEND_DESCRICAO = w.TipoEndereco.TPEND_DESCRICAO != null ? w.TipoEndereco.TPEND_DESCRICAO : w.TPEND_DESCRICAO,
UF_SIGLA = w.UnidadeFederativa.UF_SIGLA != null ? w.UnidadeFederativa.UF_SIGLA : w.UF_SIGLA,
MUN_DESCRICAO = w.Municipio.MUN_DESCRICAO != null ? w.Municipio.MUN_DESCRICAO : w.MUN_DESCRICAO
}).Distinct().AsQueryable();
return query;
}
}
}
}
When applying for inclusion in ASPxGridView a new record and the method in DAL public IQueryable <EnderecoEscola> getId (int idEsc) is invoked to retrieve the data and they do not exists it is adding a new record on the master and detail occurs error
A field or property with name 'TPEND_DESCRICAO' was not found in the
selected data source.
Someone could guide me on how to solve the problem.
Tks.