asp.net web api server data not syncing with database between BL - rest

Hello I am new to servers and REST API and am trying to extract data from a dynamically created table and the data does not sync with the data in the database.
I have an sql database from which I extracted an entity database in asp.net web project.
This is an example for GET of one entity class (exists in database):
public class EmployeeBL
{
private FSProject1Entities db = new FSProject1Entities();
public List<Employee> GetEmployees(string fname, string lname, string depID)
{
return GetEmployeeSearchResult(fname, lname, depID);
}
}
And this is an example for a method from a class such as I created in order to combine data from 2 tables:
public class ShiftEmployeeDataBL
{
private FSProject1Entities db = new FSProject1Entities();
private List<ShiftEmployeeDataBL> GetEmployeeByShiftID(int id)
{
List<ShiftEmployeeDataBL> shiftEmpData = new List<ShiftEmployeeDataBL>();
foreach (Employee emp in db.Employee)
{//build list... }
return shiftEmpData;
}
My problem is that db.Employee via this GET request path (ShiftEmployeeData) is old data and via Employee GET request is good data (assuming the data was updated via Employee path).
And vice versa - it would appear that if I update Employee via ShiftEmployeeData class, it would appear as good data for ShiftEmployeeData class and not update for Employee.
I have APIcontrollers for both classes.
what is happening? I feel like I am missing something.
I tried closing cache options in browser.
update with code for elaboration:
entity Employee:
public partial class Employee
{
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int StartWorkYear { get; set; }
public int DepartmentID { get; set; }
}
employee update(auto generated by entity model code generation from db):
public void UpdateEmployee(int id, Employee employee)
{
Employee emp= db.Employee.Where(x => x.ID == id).First();
emp.FirstName = employee.FirstName;
emp.LastName = employee.LastName;
emp.StartWorkYear = employee.StartWorkYear;
emp.DepartmentID = employee.DepartmentID;
db.SaveChanges();
}
employeeshiftdata class (not a db table but still in the models folder):
public class EmployeeShiftData
{
public int ID { get; set; } //EmployeeID
public string FirstName { get; set; }
public string LastName { get; set; }
public int StartWorkYear { get; set; }
public string DepartmentName { get; set; }
public List<Shift> Shifts { get; set; }
}
employeeshift GET part of the controller:
[EnableCors(origins: "*", headers: "*", methods: "*")]
public class EmployeeShiftDataController : ApiController
{
private static EmployeeShiftDataBL empShiftDataBL = new EmployeeShiftDataBL();
// GET: api/EmployeeShiftData
public IEnumerable<EmployeeShiftData> Get(string FirstName = "", string LastName = "", string Department = "")
{
return empShiftDataBL.GetAllEmployeeShiftData(FirstName, LastName, Department);
}
//...
}

Would need to see the code that interacts with the database, especially the code that makes the updates.
If the changes are written with Entity Framework, are the models themselves properly related with navigational properties?
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public List<EmployeeShift> EmployeeShifts { get; set; }
// etc.
}
public class EmployeeShift
{
public int Id { get; set; }
public Int EmployeeID { get; set; }
public Employee Employee { get; set; }
// etc.
}
If those are good, and both models are covered by Entity Framework's context tracking, then both should be updated.

Related

How to write the query in Entity Framewok for Stored procdure with multiple parameters

I am new to entity framework, and before I was use BLToolkit there I can use easily SQL stored procedure
public partial class AttendanceReport
{
public int AutoID { get; set; }
public string StudentID { get; set; }
public string StudentName { get; set; }
public string Class { get; set; }
public string Section { get; set; }
public string MonthName { get; set; }
public string TotalDaays { get; set; }
}
List<AttendanceReport> users = new List<AttendanceReport>();
{
using (DbManager db = new DbManager())
{
users = db
.SetSpCommand("SP_Att2Dates_Student",
db.Parameter("#StudentID", stid),
db.Parameter("#startDate", dateEdit_From.DateTime),
db.Parameter("#endDate", dateEdit_ToDate.DateTime))
.ExecuteList<AttendanceReport>();
}
}
Here AttendanceReport is the object and SP_Att2Dates_Student is Stored Procedure with three parameters.
now I am trying to write this in Entity Framework Query I have import stored procedures in Entities Model you can see in attached picture ====>Stord Procedures now how can I write a query in
using (Entities db = new Entities())
{
var users = ????????????????????????????????
}

Entity Framework fires query to load related object although explicit loading for those objects is already done

I have these models and context in my application :
public class Department
{
public int Id { get; set; }
public string Name { get; set;}
public virtual ICollection<Student> Students { get; set; }
}
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public virtual Department Department { get; set; }
}
public class TestContext : DbContext
{
public DbSet<Student> Students { get; set; }
public DbSet<Department> Departments { get; set; }
}
Below is my code in Program.cs class :
class Program
{
static void Main(string[] args)
{
using (var context = new TestContext())
{
var students = context.Students.SqlQuery("Select * from dbo.Students").ToList();
context.Departments.Load();
Console.WriteLine(students[0].Department.Name);
Console.ReadLine();
}
}
}
Although related object - Department is loaded in the context by the line - context.Departments.Load(), still when the department name is printed in console entity framework fires a query in the database to fetch the related object. Shouldnt this query for related object fetching not be fired since the objects are already loaded in the context. ?
If i change the code to below -
var students = context.Students.ToList();
context.Departments.Load();
Console.WriteLine(students[0].Department.Name);
Then when u access student[0].Department.Name , Ef doestnot fire a sql query to load department property.
Apparently Change Tracker relationship fix-up doesn't work with the combination of Independent Associations and raw SQL queries.
To fix just add Foreign Key property to Student. eg
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public int DepartmentId { get; set; }
public virtual Department Department { get; set; }
}

Entity Framework: How to query (LINQ) for data ->child-> 4 grandchildren

I have 4 classes like that:
Organization1:
Contact 1:
Phones:
phone1
phone2
Addresses:
address1
address2
Bankdata:
bankdata1
bankdata2
Contact 2:
Phones:
phone1
phone2
Addresses:
address1
address2
Bankdata:
bankdata1
bankdata2
Contact 3:
Phones:
phone1
phone2
Addresses:
address1
address2
Bankdata:
bankdata1
bankdata2
Organization 2:
... and so on...
In order to grab the list of Organizations with all its contacts and each contact including JUST the phone1 (where main == true), address1 and bankdata1 I have written the following inside Entity Framework a query:
...
public class ContactManagementRepository : IContactManagementRepository
{
public IEnumerable<Organization> getAllOrganizations()
{
return _context.Organizations
.OrderBy(o => o.organizationName)
.Include(o => o.Contacts)
.ToList();
}
...
But I just get ONE Organization, and no contacts.
A tried a second attempt like this:
public class ContactManagementRepository : IContactManagementRepository
{
public IEnumerable<Organization> getAllOrganizations()
{
return _context.Organizations.ToList();
}
...
It returns all the organizations, but not data under the tree (contact->phones, etc)
A third attempt (very bad for performance) was to get ALL the organizations and loop through using getorganizationsbyID and get the info of each one like this:
...
public Organization GetOrganizationById(Guid Id)
{
return _context.Organizations
.Include(o => o.Contacts)
.ThenInclude(c => c.Phone.main == true)
.Where(o => o.Id == Id)
.FirstOrDefault();
}
...
But it just get the organization with JUST ONE CONTACT (the first one) and not phones, address or bankdata. The method "ThenInclude" does not accept a second call. It means accept just one child under contact, but not several children.
Here are my model classes:
Organization class:
public class Organization
{
public Organization() { }
private Organization(DateTime dateCreated)
{
this.dateCreated = DateTime.Now;
Contacts = new List<Contact>();
}
public Guid Id { get; set; }
public DateTime dateCreated { get; set; }
public string organizationName { get; set; }
public string organizationType { get; set; }
public string web { get; set; }
// Contacts
public ICollection<Contact> Contacts { get; set; }
}
Contact class:
public class Contact
{
public Contact() { }
private Contact(DateTime dateCreated)
{
this.dateCreated = DateTime.Now;
Phones = new List<Phone>();
Addresses = new List<Address>();
Bankdatas = new List<Bankdata>();
}
public Guid Id { get; set; }
public DateTime dateCreated { get; set; }
public string firstName { get; set; }
public string lastName { get; set; }
public string email { get; set; }
public Guid OrganizationId { get; set; }
[ForeignKey("OrganizationId")]
public virtual Organization Organization { get; set; }
public virtual ICollection<Phone> Phones { get; set; }
public virtual ICollection<Address> Addresses { get; set; }
public virtual ICollection<Bankdata> Bankdatas { get; set; }
}
Phone class (same structure for addresses and bankdata)
public class Phone
{
public Guid Id { get; set; }
public DateTime dateCreated { get; set; }
public string phone { get; set; }
public bool main { get; set; }
// Foreign Key for Contacts
public Guid ContactId { get; set; }
//Related Organization entity
[ForeignKey("ContactId")]
public virtual Contact Contact { get; set; }
}
Database is created with the PK and FK in correctly in place (code-first)
And now I am lost. Does anybody could help with this?
How do I query (LINQ) for organization -> child -> 4 grandchildren ?
I have read literally dozens of threads here and follow tutorials in Udemy and Pluralsight without success.
EDIT
# Hadi Hassan
I followed your instructions, I created new classes OrganizationDTO, ContactDTO, AddressDTO, PhoneDTO and BankdataDTO.
I created the DTO for Bank, Phone and address because even if am sure just one is main (there is a radio button at the front end) I still will need the whole list when I get the contactsdetails.html. It will allows me to make searches by country-code and so on.
I have changed, as per your advice, but it dd not even compile. I get error telling:
*DbSet<Organization>ContactManagement.Context.Organizations {get; set;}
Cannot assign method group to an implicitly-typed variable.*
I have decided to test changing the Context class like this:
DBSet. So I changes all DBset properties with the suffix DTO. Like this:
public DbSet<OrganizationDTO> OrganizationsDTO { get; set; }
public DbSet<ContactDTO> ContactsDTO { get; set; }
public DbSet<BankdataDTO> BankdatasDTO { get; set; }
public DbSet<AddressDTO> AddressesDTO { get; set; }
public DbSet<PhoneDTO> PhonesDTO { get; set; }
But the I have got copilations error everywhere.
Best way to get your data is by relying on the DTO
so your code will appear like this
public class OrganizationDTO
{
public OrganizationDTO()
{
Contacts = new List<ContactDTO>();
}
public Guid Id{get;set;}
public string Name{get; set;}
// other needed properties goes here
public IList<ContactDTO> Contacts{get;set;}
}
public class ContactDTO
{
public ContactDTO
{
Phones = new List<PhoneDTO>();
Addresses = new List<AddressDTO>();
Banks = new List<BankDTO>();
}
public Guid Id{get;set;}
public string FirstName{get;set;}
public string LastName {get;set;}
// other required properties goes here
public IList<PhoneDTO> Phones {get;set;}
public IList<BankDTO> Banks{get;set;}
public IList<AddressDTO> Addresses{get;set;}
}
public class PhoneDTO
{
public Guid Id{get;set;}
public string Phone{get;set;}
}
public class AddressDTO
{
public Guid Id{get;set;}
public string Description{get;set;}
}
public class BankDTO
{
public Guid Id{get;set;}
public string Name{get;set;}
}
Your query then will look like
var query = _context.Organizations
.Select t=> new OrganizationDTO{
Id = t.Id,
Name = t.organizationName,
Contacts = t.Contacts.Select(c => new ContactDTO{
Id = c.Id,
FirstName = c.firstName,
LastName = c.lastName,
Phones = c.Phones.Where(p=>p.Main).Select(p=>new PhoneDTO{Id = p.Id, Phone= p.phone}),
Banks = c.Banks.Where(p=>p.Main).Select(p=>new BankDTO{Id = p.Id, Name= p.BankName}),
Addresses = c.Addressess.Where(p=>p.Main).Select(p=>new AddressDTO{Id = p.Id, Description= p.Description}),
})
}).OrderBy(t=>t.Name);
Implementing the DTO will provide many advantages for your data
Avoid Circular references
Return the required data and not all the object (Data Projection)
Allows you to combine many objects together to appear in same result, for example, in the solution I returned object BankDTO and PhoneDTO and AddressDTO which allows your to return list of object from these entities, but if you are sure that only one phone, bank , address is main, then you can instead define these data as properties in the class ContactDTO and by this you combined 4 entities data in one result.
Your ContactDTO will become as
public class ContactDTO
{
public Guid Id{get;set;}
public string FirstName{get;set;}
public string LastName{get;set;}
public string Phone{get;set;}
public string Bank{get;set;}
public string Address{get;set;}
}
and your code will be like
var query = _context.Organizations
.Select t=> new OrganizationDTO{
Id = t.Id,
Name = t.organizationName,
Contacts = t.Contacts.Select(c => new ContactDTO{
Id = c.Id,
FirstName = c.firstName,
LastName = c.lastName,
Phone = c.Phones.Where(p=>p.Main).Select(p=>p.phone).FirstOrDefault(),
Bank = c.Banks.Where(p=>p.Main).Select(p=>p.Name).FirstOrDefault(),
Address = c.Addressess.Where(p=>p.Main).Select(p=>p.Discreption).FirstOrDefault(),
})
}).OrderBy(t=>t.Name);
and in case you want to get the phone as object and not list, may be you want to get the benefit of the phone Id, you can instead of IList<PhoneDTO> to define directly PhoneDTO.
Hope this will help you

can i insert some specific fields from one table to a class

is it possible insert some specific fields from one table to a class in mvc?
for example i have tbl_User . can i insert just field "Name" in "MyClass"?
i wanna pass a model(MyClass) to view that contains some fields of tbl_User .
and i used codefirst.
public class MyClass:tbl_User
{
//i mean can i put some fields of tbl_User instead below code .
//but below code insert all fields of tbl_User
public List<tbl_User> tbl_User { get; set; }
}
Yes, you can; see the code below.
// get /users
public ActionResult Index()
{
using (var db = new YourContext())
{
// We just need to show user name and id will be used to perform actions like edit user ETC. So we have created a reduced model named UserIndexModel.
return db.Users.Select(u => new UserIndexModel { Id = u.Id, Name = u.Name}).ToList();
}
}
Model definitions:
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public string HashPassword { get; set; }
public DateTime CreatedOn { get; set; }
}
public class YourContext : DbContext
{
public DbSet<User> Users { get; set; }
}
View model:
public class UserIndexModel
{
public int Id { get; set; }
public string Name { get; set; }
}

.Net MVC 4 REST Cannot send Object

I have build a .Net Mvc 4 application and now I want to extend it with REST.
I am using the Entity Framework and I have the following problem.
My goal is to have a system where categories have a number of products and where products can belong to multiple categories.
As follows:
public class Categorie
{
[Key]
public int Id { get; set; }
[Required]
public string Naam { get; set; }
[Required]
public string Omschrijving { get; set; }
public byte[] Plaatje { get; set; }
private List<Product> producten;
public virtual List<Product> Producten
{
get { return producten; }
set { producten = value; }
}
}
public class Product
{
[Key]
public int Id { get; set; }
[Required]
public string Naam { get; set; }
[Required]
public string Omschrijving { get; set; }
[Required]
public double Prijs { get; set; }
private List<Categorie> categorien = new List<Categorie>();
public virtual List<Categorie> Categorien
{
get { return categorien; }
set { categorien = value; }
}
[Required]
public byte[] Plaatje { get; set; }
}
NOTE: There are virtual properties in there so that my entity framework creates a merging table. Normally it links all the categorie's to the products and vice versa.
And my rest looks like:
// GET api/Rest/5
public Product GetProduct(int id)
{
Product product = db.Producten.Find(id);
Product newProduct = new Product();
if (product == null)
{
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
}
else
{
product.Categorien = null;
}
newProduct.Id = product.Id;
newProduct.Naam = product.Naam;
newProduct.Omschrijving = product.Omschrijving;
newProduct.Plaatje = product.Plaatje;
newProduct.Prijs = product.Prijs;
newProduct.Categorien = product.Categorien;
return newProduct;
}
First problem: I cannot send any product aslong as it has a categorie. I have to make it null.
Second problem: I cannot send the original product because of the first problem.
I am assuming your problem is with a circular reference during serialization, since categories reference multiple products and products reference multiple categories. One solution is to use Data Transfer Objects (DTO) instead of returning the straight entities you are using for EF. To make it easy to map your entities to the DTO's I would use AutoMapper. This is essentially what you are doing when you create an instance of newProduct in your REST API method, but AutoMapper takes the hard coding and drudgery out of mapping. Your DTO for a product would look very similar but they would not have the virtual navigation properties or the attributes needed by EF. A DTO for a product would look something like this.
public class Categorie
{
public int Id { get; set; }
public string Naam { get; set; }
public string Omschrijving { get; set; }
public byte[] Plaatje { get; set; }
}
public class Product
{
public int Id { get; set; }
public string Naam { get; set; }
public string Omschrijving { get; set; }
public double Prijs { get; set; }
public List<Categorie> categorien = new List<Categorie>();
public List<Categorie> Categorien
{
get { return categorien; }
set { categorien = value; }
}
public byte[] Plaatje { get; set; }
}
Notice that the DTO for Categorie does not contain a list of products, since in this case you want a listing of products. If you keep the field names the same for your DTO's as your entities AutoMapper will handle the mapping automatically. I usually keep the same class name for the DTO's and just distinguish them from the entities by having a different namespace. Your REST API method would look something like this.
// GET api/Rest/5
public Product GetProduct(int id)
{
Product product = db.Producten.Find(id);
return Mapper.Map<Product, Dto.Product>(product);
}