How do I create a Breeze entity of a derived class? - breeze

In a breeze model with a simple TPH inheritance structure, I can't work out how to correctly create a new breeze entity of a child type.
For example:
public class Vehicle
{
public string Name { get; set; }
public byte VehicleType { get; set; }
}
public class Car : Vehicle
{
// Some extra properties
}
The discriminator does not follow the standard Entity Framework approach of using a string value to determine a class's parent so we use some EF FluentAPI to modify the metadata:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Vehicle>()
.Map<Car>(m => m.Requires("VehicleType").HasValue((byte)1));
}
The default behaviour from the code below appears to create a suitable entity in Breeze but the discriminator value is never set so saving changes to the server results in the persistence of an object of type Vehicle instead of Car.
var group = breezeManager.createEntity("Car", {
Name: 'My car'
// If the line below is omitted, VehicleType is saved
// to the server with a value of 0
,VehicleType: 1
});
breezeManager.saveChanges();
Although this appears to be a question about the behaviour of the client-side component of Breeze, it might be relevant that we are using Breeze to store into a database that is not accessed via the Entity Framework (we just generate EF metadata for Breeze to consume).
I don't think that the client-side code should have to worry about the implementation of our inheritance discriminators so hopefully there is an alternative to manually setting the value when we create every object.
What is the best way to correctly store the discriminator value?

I was able to verify that TPH with byte discriminator value works. The only difference that I notice between my model and yours is that I didn't specify the byte property in mine.
public abstract class Airplane
{
public int Id { get; set; }
public string Name { get; set; }
//public byte AirplaneType { get; set; } //Not required
}
public class Boeing : Airplane
{
public string Model { get; set; }
}
Specifying the discriminator in the Fluent API was enough to let EF saves the right value.

Related

How to add complex properties on a model built with ODataConventionModelBuilder from an EF model

I have a model that is defined in EF database first edmx. From there I expose some tables and views (mainly views). As it's possible to augment the EF model with OData, how could I add a navigation property of a complex type to another EF and OData exposed type?
Currently I define a partial class and add the properties and attributes using them. But it looks like it's possible to add the desired properties with OData's modelbuilder functionality too, or perhaps better yet, first use ODataConventionModelBuilder and then augment the results. Alas, I'm unable to stitch together a working example from the existing API documentation and examples I've found.
Here's the code
//This class is generated from a view by EF (edmx)...
public partial class AccountView
{
public System.Guid Id { get; set; }
public int CompanyId { get; set; }
}
//Here's augmenting the EF generated view with some additional data...
[MetadataType(typeof(AccounViewMetaData))]
public partial class AccounView
{
//This is added here explicitly. AccountView itself exposes just
//a naked key, CompanyId.
public virtual Company Company { get; set; }
//This is just in case...
public class AccounViewDomainMetaData
{
//This is to add a navigation property to the OData $metadata. How to do this
//in WebApiConfig? See as follows...
[ForeignKey("Company")]
public int CompanyId { get; set; }
}
}
//This is an EF generated class one from an edmx..-
public partial class Company
{
public Company() { }
public int CompanyID { get; set; }
public string Name { get; set; }
}
//How to add a navigation property from AccountView to Company so that it'd become
//possible to call http://example.com/Accounts?$expand=Company and http://example.com/Accounts(1)?$expand=Company ?
var builder = new ODataConventionModelBuilder();
var companySet = builder.EntitySet<Entities.Company>("Companies");
var accountSet = builder.EntitySet<Entities.AccountView>("Accounts");
accountSet.EntityType.HasKey(i => i.Id); //EF has hard time recognizing primary keys on database first views...
//How to hide this from the result if there's a way to create a ?$expand=Company navigation property?
//accountSet.EntityType.Ignore(i => i.CompanyId);
This is related to my other question regarding OData and models.

Inherit from Entity class so it can be used in Entity Framework

I am having a problem with the Entity Framework code-first approach:
public class Entity
{
[Key]
public int Id { get; set; }
public string A { get; set; }
}
public class Context : DbContext
{
public DbSet<Entity> Entities { get; set; }
}
Let's say this is the setup for the Entity Framework. It works. I can create an Entity instance and Add it to the Entities set. Now my problem is: I want to create a subclass of Entity that is a ViewModel passed to some view:
public class EntityViewModel : Entity
{
public String ViewModelProperty { get; set; }
}
Then, when I get back the resulting object from the model binder, I should be able to do this:
public void Action(EntityViewModel vm)
{
db.Entities.Add(vm); // This should work since EntityViewModel inherits Entity
db.SaveChanges();
}
Here, I get the following Exception:
Mapping and metadata information could not be found for EntityType 'EntityViewModel'.
I already tried adding the [NotMapped] attribute to EntityViewModel, this doesn't help.
If I manually extract the EntityViewModel properties into a new Entity object, it works:
public void Action(EntityViewModel vm)
{
var entity = new Entity
{
Id = vm.Id,
A = vm.A
};
db.Entities.Add(entity); // This works!!!
db.SaveChanges();
}
Why does the EntityFramework behave this way? Is there a way to tell it to ignore EntityViewModel objects?
Thanks in advance.
This will not work because EF understands your inheritance as a Table per Hierarchy scheme, so it expects to have the properties of EntityViewModel on the same table as the properties for Entity.
You can use composition to avoid this problem:
public class EntityViewModel : Entity
{
public Entity Entity { get; set; }
public String ViewModelProperty { get; set; }
}
And then
public void Action(EntityViewModel vm)
{
db.Entities.Add(vm.Entity);
db.SaveChanges();
}
Check this answer for complex objects model binding rules.
Good luck.
A better approach would be to use composition rather than inheritence. In this instance, the view model could either expose the model directly to the view, or delegate through to the model.

Establish Foreign Key Connection Using Entity Framework With SQL Queries

I have a couple of classes (for this example anyway) that use code first with the entity framework to connect to the database.
public class Customer
{
[Key]
public long CustomerId { get; set; }
public string CompanyName { get; set; }
...
public virtual List<Contact> Contacts { get; set; }
}
public class Contact
{
[Key]
public long ContactId { get; set; }
public string Forename { get; set; }
...
public long CustomerId { get; set; }
public virtual Customer Customer { get; set; }
}
When I hook these up in my context class directly to the db the foreign key relationships hook up fine and I can access the collection of contacts from within the customer class.
class RemoteServerContext : DbContext
{
public DbSet<Customer> Customers { get; set; }
public DbSet<Contact> Contacts { get; set; }
...
}
My problem is that these database tables are used by various different systems and are massive. In order to increase efficiency I have overridden the default behaviour to point at a view (and also a stored proc elsewhere) rather than directly at the table.
public IEnumerable<Customer> Customers ()
{
return Database.SqlQuery<Customer>("SELECT * FROM vw_CustomerList");
}
public IEnumerable<Contact> Contacts()
{
return Database.SqlQuery<Contact>("SELECT * FROM vw_ContactsList");
}
I have made sure that in each of the views I have included the foreign key fields: CustomerId and ContactId.
When I do this however the class joins appear to be lost - there's always a null when I drill into either of the objects where it should be pointing to the other one. I have tried to set up what the foreign key field should point to but this doesn't seem to help either.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Contact>().HasRequired(p => p.Customer)
.WithMany()
.HasForeignKey(k => k.CustomerId);
}
Is there a way to establish the connection when overriding the default behaviour?
There is no overriding in this case. If you removed
public DbSet<Customer> Customers { get; set; }
and replaced it with
public IEnumerable<Customer> Customers ()
{
return Database.SqlQuery<Customer>("SELECT * FROM vw_CustomerList");
}
you have completely changed the behavior. The first uses entities and full power of EF. The second is only helper to execute custom SQL. Second without first or without defining entity in OnModelCreating doesn't use Customer as mapped entity at all - it uses it as any normal class (only mapped entities can use features like lazy loading).
Because your Customer is now mapped to view you cannot use your former Customer class used with table. You must define mapping of Customer to a view by cheating EF:
modelBuilder.Entity<Customer>().ToTable("vw_ContactsList"); // EF code fist has no view mapping
Once you have this you can try again using:
public DbSet<Customer> Customers { get; set; }
Unless your view is updatable you will get exception each time you try to add, update or delete any customer in this set. After mapping relation between Customer and Contact mapped to views your navigation properties should hopefully work.
The problem with SqlQuery is the way how it works. It returns detached entities. Detached entities are not connected to the context and they will not lazy load its navigation properties. You must manually attach each Customer instance back to context and to do that you again need DbSet.

MVC and EF4 CTP model-binding and saving hierarchical model

Am having trouble finding a clear answer to my situation when searching Stack Overflow and Google, hopefully someone can point me in the right direction.
My Situation
I want to be able to use a single edit form (in a single View) to update a 3-level-deep hierarchical entity using ASP.NET MVC 3 and Entity Framework 4 CTP (Code-first) - the model consists of Services, which can have many Service Options, which in Turn can have many Inventory Items.
I was expecting to be able to use MVCs default model binder (via TryUpdateModel) to:
Update an existing 'Service' record
Add/Update/Delete 'Service Option' records (attached to the Service) depending on posted values
Add/Update/Delete 'Inventory' records (attached to each Service Option) depending on posted values
My Model
[Bind(Include="Name, ServiceOptions")]
public class Service {
[Key]
public int ServiceID { get; set; }
public string Name { get; set; }
public DateTime DateCreated { get; set; }
public virtual ICollection<ServiceOption> ServiceOptions { get; set; }
}
[Bind(Include="ServiceOptionID, Description, Tags")]
public class ServiceOption {
[Key]
public int ServiceOptionID { get; set; }
public int ServiceID { get; set; } /* parent id reference */
public string Description { get; set; }
public virtual ICollection<Inventory> InventoryItems { get; set; }
}
[Bind(Include = "InventoryID, Description")]
public class Inventory {
[Key]
public int InventoryID { get; set; }
public int ServiceOptionID { get; set; } /* parent id reference */
public string Description { get; set; }
}
Ideal Controller Method:
[HttpPost]
public ActionResult EditService(int id) {
Service service = db.Services.Single(s => s.ServiceID == id);
TryUpdateModel(service); // automatically updates child and grandchild records
if (ModelState.IsValid) {
db.SaveChanges();
return RedirectToAction("Index");
}
return View(service);
}
Is there a way to achieve this utopian dream, or am I barking up the wrong tree? I'm open to using another technology (such as normal EF4, Automapper etc)
Thanks in advance!
With just the default model binder? Probably not.
With a custom one? Probably.
However your issue won't be the model binder itself. Your issue will be that EF and ORMs and ( I think ) in general do not consider removing an item from a collection as a delete operation. In effect what you are telling the ORM is the relationship does not exist, not that a child row needs to be deleted. Depending on your mappings you'll usually get an error like "A referential integrity constraint violation occurred". This won't be because of code first this is just how EF works.
EF works this way by design and is really important for more complex relationships such as when you have m2m relationships which reference other m2m relationships. You really want EF to be able to disambiguate calls for removal of a relationship and calls to remove a row entirely.
Also, IMHO, this technique is also bad because your letting the piece of code responsible for mapping http values also dictate how objects should be persisted. This is a bad move. I consider delete operations a pretty sacrosanct act and shouldn't be left to the ModelBinder alone. Without soft deletes or logging deleting objects should be considered "serious business".

Support for nested model and class validation with ASP.NET MVC 2.0

I'm trying to validate a model containing other objects with validation rules using the System.ComponentModel.DataAnnotations attributes was hoping the default MVC implementation would suffice:
var obj = js.Deserialize(json, objectInfo.ObjectType);
if(!TryValidateModel(obj))
{
// Handle failed model validation.
}
The object is composed of primitive types but also contains other classes which also use DataAnnotications. Like so:
public class Entry
{
[Required]
public Person Subscriber { get; set; }
[Required]
public String Company { get; set; }
}
public class Person
{
public String FirstName { get; set;}
[Required]
public String Surname { get; set; }
}
The problem is that the ASP.NET MVC validation only goes down 1 level and only evaluates the properties of the top level class, as can be read on digitallycreated.net/Blog/54/deep-inside-asp.net-mvc-2-model-metadata-and-validation.
Does anyone know an elegant solution to this? I've tried xVal, but they seem to use a non-recursive pattern (http://blog.stevensanderson.com/2009/01/10/xval-a-validation-framework-for-aspnet-mvc/).
Someone must have run into this problem before right? Nesting objects in your model doesn't seem so weird if you're designing a web service.
I suggest looking into Fluent Validation from codeplex. The validation rules are contained in a separate class (similar to the way NHibernate and Fluent NHibernate work). One uses a lambda to specify the property to validate, supporting child properties.
`
public class MaintainCompanyViewModelValidator : AbstractValidator<MaintainCompanyViewModel>
{
public MaintainCompanyViewModelValidator()
{
RuleFor(model => model.Company.ShortName)
.NotEmpty();
}
`

Resources