BreezeController Controller Issue - entity-framework

I have a simple BreezeController that returns a unit of work repository object. The object is a DbSet entity object of the class below:
public int OrderId { get; set; }
public string Customer { get; set; }
public virtual ICollection<OrderLine> OrderLines { get; set; }
The Unit of Work class is as follows:
private readonly EFContextProvider<ESpaDBEntities> _contextProvider;
public UoW()
{
_contextProvider = new EFContextProvider<ESpaDBEntities>();
Orders = new Repository<Order>(_contextProvider.Context);
OrderLine = new Repository<OrderLine>(_contextProvider.Context);
Products = new Repository<Product>(_contextProvider.Context);
}
public IRepository<Order> Orders { get; set; }
public IRepository<OrderLine> OrderLine { get; set; }
public IRepository<Product> Products { get; set; }
public SaveResult Commit(JObject changeSet)
{
return _contextProvider.SaveChanges(changeSet);
}
The BreezeController action is as follows:
[HttpGet]
public IQueryable<Order> Orders()
{
return uow.Orders.All();
}
When I access this method from my browser the following Json object is returned:
$id: "1",$type: "KoDurandalBreeze.DomainModel.Order, KoDurandalBreeze",OrderId: 1,Customer: "Bob",OrderLines: [ ]
For whatever reason, orderlines are not populated even though virtual is specified. Does anyone have any ideas of why the JSON object would not contain any OrderLine objects?

You will need to either perform the equivalent of an EF 'Include' on the server or if this is an EF Queryable you can call 'extend' on your client side EntityQuery, i.e.
var query = EntityQuery.from("Orders").expand("OrderDetails");
var myEntityManager.executeQuery(query).then(...)

Related

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

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.

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 .Include Load Tables Joined in Different Context

Quite new with LINQ. I am wondering how I would be able to achieve this.
I have the following table classes defined:
public partial class Cars
{
public long ID { get; set; }
public string CarName { get; set; }
public long CarModelID { get; set; }
public virtual CarModel CarModel { get; set; }
}
public partial class CarModel
{
public long ID { get; set; }
public string ModelName { get; set; }
public long StockID { get; set; }
}
public partial class Stock
{
public long ID { get; set; }
public string StockName { get; set; }
}
There's also a defined extension for the class Cars (Cars.extension.cs):
public partial class Cars
{
public List<Stock> StockList { get; set; }
}
I am trying to get all the Cars, CarModel and (List of) Stocks via the following query:
var query = (from cars in Context.Cars.Include("CarModel").Include("StockList")
select cars).FirstOrDefault();
It is giving me an error:
"A Specified Include Path is not Valid. The Entity Type Cars does not declare a Navigation Property with the name 'StockList'"
How would I be constructing my LINQ query such it would include possibly the list of Stocks based on a CarModel based off Cars?
The Include method is adhering to FluentAPI principles, that means further Include() calls are still in the context of the parent entity (Cars) and not in the previously included CarModel.
What you need is:
Cars.Include("CarModel.StockList")
Or
Cars.Include(x => x.CarModel.StockList)

WCF + EF return object with FK

I am facing following issue: I have ProductOrder class which has ProductId as foreign key to Product class. When I invoke following method:
public IEnumerable<ProductOrder> GetOrders()
{
return OddzialDb.ProductOrders;
}
Orders are associated with Product so I can write something like this:
OddzialDb.ProductOrders.First().Product.Name;
but when it reaches Client it turns out that there is no association with Product which is null (only ProductId is included). In DbContext I have set
base.Configuration.ProxyCreationEnabled = false;
base.Configuration.LazyLoadingEnabled = false;
On the WCF Service side auto-generated by EF ProductOrder class looks as follows:
public partial class ProductOrder
{
public int Id { get; set; }
public Nullable<int> ProductId { get; set; }
public int Quantity { get; set; }
public virtual Product Product { get; set; }
}
What happens that it looses connections with tables associated by foreign keys?
Make your relationship virtual as in the example:
public class ProductOrder
{
public int Id { get; set; }
public virtual Product Product { get; set; }
public int ProductId { get; set; }
}
By turning your relationship virtual, the Entity Framework will generate a proxy of your ProductOrder class that will contain a reference of the Product.
To make sure it will work, Product also has to contain reference to ProductOrder:
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<ProductOrder> ProductOrders { get; set; }
}
Set these variables true on your DbContext:
Configuration.LazyLoadingEnabled = true;
Configuration.ProxyCreationEnabled = true;
On your WCF application, add the following class, which will allow for proxy serialization:
public class ApplyDataContractResolverAttribute : Attribute, IOperationBehavior
{
public ApplyDataContractResolverAttribute()
{
}
public void AddBindingParameters(OperationDescription description, BindingParameterCollection parameters)
{
}
public void ApplyClientBehavior(OperationDescription description, System.ServiceModel.Dispatcher.ClientOperation proxy)
{
DataContractSerializerOperationBehavior dataContractSerializerOperationBehavior =
description.Behaviors.Find<DataContractSerializerOperationBehavior>();
dataContractSerializerOperationBehavior.DataContractResolver =
new ProxyDataContractResolver();
}
public void ApplyDispatchBehavior(OperationDescription description, System.ServiceModel.Dispatcher.DispatchOperation dispatch)
{
DataContractSerializerOperationBehavior dataContractSerializerOperationBehavior =
description.Behaviors.Find<DataContractSerializerOperationBehavior>();
dataContractSerializerOperationBehavior.DataContractResolver =
new ProxyDataContractResolver();
}
public void Validate(OperationDescription description)
{
// Do validation.
}
}
Then on your ServiceContract interfaces you add the DataAnnotation [ApplyDataContractResolver] right among your other annotations such as [OperationContract], above any method signature that returns an entity:
[OperationContract]
[ApplyDataContractResolver]
[FaultContract(typeof(AtcWcfEntryNotFoundException))]
Case GetSingleByCaseNumber(int number);

.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);
}