Custom metadata from EFcontextprovider using POCO and ObjectCotext - c#

I am new in breezejs and trying to develop an SPA with angular-breeze.
I have a class named POCOObjectContext which is inherited from the base class ObjectContext. My Database has a table named Customer and as well as I have a POCO named Customer. But I have some extra properties on the POCO Customer, like Email, SupplierName which are not the table columns. When I take the Metadat() from EFContextProvider it provides me only the columns which are in the table named Customer. But the context that holds the POCO named Customer, have all the properties i have declared. As a result in BreezeJS, while creating object from breeze.EntityManager, it is created according to the columns in the Customer Table, but i need these extra properties in the Metadata to get and save data from/to my database. Any help will be highly appreciated...
This is Context Class POCOObjectContext (tmpDataBaseEntities is ConnectionString)
public class POCOObjectContext : ObjectContext
{
private ObjectSet<Customer> customers;
public POCOObjectContext()
: base("name=tmpDataBaseEntities", "tmpDataBaseEntities")
{
customers = CreateObjectSet<Customer>();
}
public ObjectSet<Customer> Customers
{
get { return customers; }
}
}
This is POCO Customer which holds extra properties SupplierName and Email
public class Customer
{
[Key]
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string SupplierID { get; set; }
//Extra Properties not in the Customer Table as Columns
public string SupplierName { get; set; }
public string Email { get; set; }
}
Finally the Breeze Controller
[BreezeController]
public class ReceiveServiceController : ApiController
{
EFContextProvider<POCOObjectContext> _pocoContext = new EFContextProvider<POCOObjectContext>();
ReceiveDal _rcvDal = new ReceiveDal();
[HttpGet]
public string Metadata()
{
var t = _pocoContext.Metadata();
return t; // It holds the properties info that match with POCO and Database Table.
}
}

As you have discovered, custom unmapped properties on the server are not included in the metadata definition sent to the client. You can, however, extend your client's Customer definition by doing something like this,
//Assuming you have camelCase naming convention enabled
function Customer() {
this.supplierName = '';
this.email = '';
}
entityManager.metadataStore.registerEntityTypeCtor('Customer', Customer);
Now when you call saveChanges, Breeze will include the above custom properties in the payload.
{"Id": 42, "Name": "Customer Name","__unmapped":{"supplierName":"Supplier Name", "email": "supplier#supplier.com"},...}
Then, on the server, you can examine and parse the JObject payload to retrieve the unmapped properties.
You can read more about extending Breeze entities on the client at http://www.breezejs.com/documentation/extending-entities
Hope this helps.

Related

How can you add properties annotated with PrimaryKey to existing RealmObject model objects in Realm .NET?

I am using Realm .NET to store model objects in a realm database. I have an existing model object called Employee with a single property:
public class Employee : RealmObject
{
public string Username { get; set; }
}
The Realm database already contains a few instances of this type.
I am now trying to add a new property to the object which should be annotated with the [PrimaryKey] attribute. The desired new version of the object should look like this:
public class Employee : RealmObject
{
[PrimaryKey]
public string Id { get; set; }
public string Username { get; set; }
}
Since the new Id property will not contain suitable values for the existing database objects, I am trying to use the migration feature in Realm to seed their values. The code to perform the Realm migration looks like so:
private void MigrateToSchemaVersionWithEmployeeIds(Migration migration)
{
var employees = migration.NewRealm.All<Employee>();
foreach (var employee in employees)
{
employee.Id = Guid.NewGuid().ToString();
}
}
When starting the app, the migration code is executed but when assigning to the Id property, an Exception is thrown:
System.InvalidOperationException: Once set, primary key properties may not be modified.
As a workaround, I have determined that you can first add the property without the [PrimaryKey] attribute, have its values seeded in the migration code (no exception is thrown in this case), stop the app, add the [PrimaryKey] attribute to the property, increase the schema version and relaunch the app. As this is no workable solution for when an app is already deployed in production, I am looking for a way to achieve this without having to use such a workaround.
How can a property with a [PrimaryKey] attribute be added to an existing model object in Realm .NET?
That is unfortunately, not possible. As a workaround, you can map your Employee class to a new table like:
[MapTo("Employee2")]
public class Employee : RealmObject
{
[PrimaryKey]
public string Id { get; set; }
public string Username { get; set; }
}
It will allow you to keep using it as Employee for all intents and purposes, but in the database itself it will be persisted as Employee2. Then in the migration block, you could do:
private void MigrateToSchemaVersionWithEmployeeIds(Migration migration)
{
var employees = migration.OldRealm.All("Employee");
foreach (var employee in employees)
{
var newEmployee = new Employee
{
Id = Guid.NewGuid().ToString(),
Name = employee.Name
};
migration.NewRealm.Add(newEmployee);
}
}

Reading data from DB using Entity Framework results in missing fields of an object

I currently have 2 models. One model references the other model. I am able to write the data perfectly well to the db. however when I read the data I get an incomplete object. One of the fields of that object is missing. This is what my models look like
public class Student
{
public int Id { get; set; }
public List<Sport> Sports { get; set; }
public string StudentName { get; set; }
}
public class Sport
{
public int Id { get; set; }
public string SportName { get; set; }
}
public class DbContext : DbContext
{
public DbContext()
: base("name=StudentContext")
{
}
public DbSet<Student> Students { get; set; }
}
Now I am writing the Student object like this
//Writing to the DB
Student stud = new Student()
{
StudentName = "Andrew",
};
stud.Sports = sportList; //Contains a sport List
this.context.Students.Add(device);
this.context.SaveChanges();
After writing the object to the DB I noticed that both the tables got populated and it looks good. However when I attempt to read the object back like this
The Sport List in Student does not get populated and comes back as NULL
//Reading from DB - Sports field missing
var a = this.context.Students.FirstOrDefault();
List<Sport> actions = a.Sports; //Returns null Why ??
Any suggestions on what I might be doing wrong ? How can I get the sports field as well ?
change in edmx file
<EntityContainer Name="StudentContext" annotation:LazyLoadingEnabled="false">
OR
{
public DbContext()
: base("name=StudentContext")
{
this.Configuration.LazyLoadingEnabled = false;
this.Configuration.ProxyCreationEnabled = false;
}
public DbSet<Student> Students { get; set; }
}
Or you can also modify your query
var a = this.context.Students.Include(s => s.Sports).FirstOrDefault();
Actually you do NOT need to do this (and you should not because in this way all the navigation properties inside the current DbContext will be eager loaded):
this.Configuration.LazyLoadingEnabled = false;
According to the reference you have already disabled lazy loading for the navigation property Sports by declaring it as a non-virtual property.
Loading of the Sports collection can still be achieved using eager loading or the Load method.
(Adapted to this case from the doc)

How to insert the value to forignkey column using C# mvc entityframwork

I have an employee Salary table, The primary key is SSID.So I have created another table Employee information SSID will be a foreign key on that table. Now the problem is I want to insert the value to Employee information table.
the issue is how to insert value the Forignkey column using MVC or how we bring the primary key value to the foreign key.
I am new to this. I am doing CRUD operation .is i need to join the table. because I am using entity framework and angular js so how we write the code MVC controller and view.please
You have to build an association between the two tables.
[Table("EmployeeSalary")]
public class EmployeeSalary
{
public EmployeeSalary()
{
EmployeeInfo = new HashSet<EmployeeInfo>();
}
[Key]
public Int16 SSID { get; set; }
….
public virtual ICollection<EmployeeInfo> EmployeeInfo { get; set; }
}
public class EmployeeInfo
{
public Int16 SSID { get; set; }
….
[ForeignKey("SSID")]
public virtual EmployeeSalary EmployeeSalary { get; set; } }
If I understand this correctly, employee information could have many employee salaries hence your models should look like;
public class EmployeeInformation{
public int EmployeeInformationId {get;set;}
public virtual List<EmployeeSalary> EmployeeSalaries {get;set;}
}
public class EmployeeSalary{
public int EmployeeSalaryId {get;set;}
public int EmployeeInformationId {get;set;}
[ForeignKey("EmployeeInformationId")]
public virtual EmployeeInformation EmployeeInformation {get;set;}
}
Then in your Employee Information view, you should have a link or a button that redirect you to add Employee Salaries. This link should contain the Employee Information Id inside an anonymous object.
#Html.Action("AddSalary", new { id = Model.EmployeeeInformationId })
In my example above, I used the action name "AddSalary" there should be a AddSalary method in the Controller to handle this request. So in your EmployeeInformation Controller you should have;
public class EmployeeInformationController:Controller
{
...
public ActionResult AddSalary(int eId)
{
new EmployeeSalary es = new EmployeeSalary();
es.EmployeeInformationId = eId;
return View(es);
}
}
Your AddSalary view should use the EmployeeSalary Model, then with the controller action example above, it will auto populate the Employee Information Id with the one passed through the url.

BreezeJS lookup with navigation property

I am starting to use breezejs for a project with a Web API 2.1 backend. I have an entity called Country that has a foreign key/navigation property to an entity called Continent.
I want to use the countries as lookup values but I also need their relationship to continents so I would like to fetch that info as well.
public class Country
{
public string Iso { get; set; }
public string Name { get; set; }
public virtual Continent Continent { get; set; }
}
I also have a FK field called continentIso but I don't use it in code.
Currently the backend controller looks like:
[HttpGet]
public object Lookups() {
var countries = _breezeRepository.Get<Country>().Include(it=>it.continent);
//more lookups in here
return new { countries };
}
As per the breeze samples I am returning an anonymous object of entities (I have a couple more but removed them from the above to avoid confusion).
On the front end side I have a lookup repository (demonstrated by John Papa's Building Apps with Angular and Breeze - Part 2):
function setLookups() {
this.lookupCachedData = {
countries: this._getAllLocal(entityNames.country, 'name'),
};
}
Problem is that although the sent JSON contains values for the continents, the countries object does not contain a value or a navigation property for them.
I have also tried bringing the continents as a separate lookup and try joining them through breeze metadata extension as I do for connecting lookups with entities but to no avail.
I also have a FK field called continentIso but I don't use it in code.
Probably that's the problem as explained here.
I would try the followings:
Make sure you have the Continent FK explicitly defined in your domain model. Eg.:
public class Country
{
public string Iso { get; set; }
public string Name { get; set; }
public string ContinentIso { get; set; }
public virtual Continent Continent { get; set; }
}
Also, in your controller, return not only the list of countries, but also the list of continents; breeze would make the binding. (not sure that the Include your have there is necessary).
[HttpGet]
public object Lookups() {
var countries = _breezeRepository.Get<Country>();
var countinents = _breezeRepository.Get<Continent>();
//more lookups in here
return new { countries, continents };
}

Need to add extra column for processing

I have table called Customer with
CustomerID
Name
Salary etc.
I have added Customer table object to dbml, now on top of Customer table columns I need to add IsProcessed column.
I have added it but it throws exception while retrieving data as "invalid column IsProcessed"
Do i need to create separate POCO object and add extra column
Later fill in the new list with POCO object from db list.
Any alternative solution? Please advise
You can extend class generated from DBML by creating partial class in new file :
public partial class Customer
{
public bool IsProcessed { get; set; }
}
put codes above in new class file and set it's namespace the same as your DBML generated Customer class.
This is common pattern to be able to extend generated class without worrying the extension codes overridden if DBML file regenerated.
[For Reference]
If the models get out of sync with the database and saving the EDMX file and running the “Update Model from Database…” feature doesn’t work, then consider this link
http://blog.jongallant.com/2012/08/entity-framework-manual-update.html#.Uwrul_mSzkA
public class CustomerData
{
public int CustomerID { get; set; }
public string Name { get; set; }
public double Salary { get; set; }
public bool IsProcessed { get; set; }
}
LINQ query:
List<CustomerData> GetData()
{
var data = from cus in context.Customer
select new CustomerData{
CustomerID = cus.CustomerID,
Name = cus.Name,
Salary = cus.Salary
IsProcessed = Your custom field data
};
return data.ToList();
}

Categories