Entity framework Association in conceptual model for one to many relationship - entity-framework

I have two entity CUSTOMER and ORDER..there is one to many relation from CUSTOMER to ORDER where CustomerID is primary key for customer and foreign key in ORDER..now I want to add customer name property from CUSTOMER entity in ORDER entity...I have copied this property and paste it in ORDER table and have added CUSTOMER table and map this property to the CUSTOMER table's same property..but when i trying to validate it vs giving me a Error that is
3024: Problem in mapping fragments starting at line 239:Must specify
mapping for all key properties (ORDER.OrderID) of the EntitySet ORDER

That is not possible in mapping. You cannot add property from Customer table into Order entity this way. Mapping properties from multiple tables to the same entity has very strict rules and it is not possible for this case.
You can expose customer's name in your Order class without defining it in the mapping. Create partial part of Order class and add custom computed property (non mapped):
public partial class Order
{
public string CustomerName
{
get
{
// Customer is navigation property to Customer entity
return Customer.Name;
}
}
}
This will require loading Customer with your Order (eager loading) or using lazy loading. Also this property cannot be used in Linq-to-entities queries.

Related

Entity Framework is appending "1" to table name and query is failing

We have an e-commerce site that uses Web Api and Entity Framework. I recently had created an ApiController for an entity called "BundleProduct". When I call the GET method on the controller, I get a System.Data.SqlClient.SqlException: "Invalid object name 'dbo.BundleProducts1'."
Using the VS debugger, this is the query that was being executed (there are only two columns in this table, with together form a primary key):
SELECT
[Extent1].[Fk_BundleID] AS [Fk_BundleID],
[Extent1].[Fk_ProductID] AS [Fk_ProductID]
FROM [dbo].[BundleProducts1] AS [Extent1]
There is no "BundleProducts1" table, it should be called "BundleProducts". I did a search in the code and cannot find any instances where the name "BundleProducts1" is used.
The BundleProducts table represents a many-to-many relationship between a "Bundles" table and "Products" table. This particular table has only two columns and both together are the primary key. I did look at the DbContext class and the only references it has to BundleProducts are:
public DbSet<BundleProduct> BundleProducts { get; set; }
modelBuilder.Entity<Bundle>()
.HasMany(e => e.Products)
.WithMany(e => e.Bundles)
.Map(m => m.ToTable("BundleProducts")
.MapLeftKey("Fk_BundleID")
.MapRightKey("Fk_ProductID"));
Why is EF appending a "1" to the table name and what can I do to change this?
When you use the many-to-many mapping (HasMany - WithMany), EF will use a hidden association class named BundleProducts.
The problem is that you also added a visible class BundleProducts. EF tries to do what you instructed it to do: map both classes to a table and then it encounters a name conflict. The visible class is victimized and is renamed.
You either have to remove the visible class from your model, or transform the many-to-many mapping into two one-to-many mappings with BundleProducts in the middle: Bundle 1 - n BundleProduct n - Product.

Entity Framework associations with nullable columns and without foreign keys

I am attempting to use Entity Framework with a database that does not make use of foreign keys. To make matters worse, tables that have a relationship make use of relating fields that can be null. For example the Order table has a column for ClientID that is nullable. Keeping in mind I did not create this database nor can I change it I would like to still be able to use Entity Framework (v6.1) to perform CRUD operations on the database.
The problem, as you might expect, has to do with the association between entities. I can create the associations myself manually but I cannot set the referential integrity because the properties in the entities map to columns in the database that can be NULL.
Is there a way to get around this? Perhaps a way to use the associations without having to define referential integrity? Granting that it would be up to me to make sure that any child records be deleted if a given parent is deleted..
I think this will work:
public class Order
{
//other properties
public int? ClientId {get; set;}
}
And set
modelBuilder.Entity<Order>()
.HasOptional(x=>x.Client)
.WithMany(x=>x.Orders)
.WithForeignKey(x=>x.CliendId);

Entity Framework: removing entity when One-to-One PK association is specified

I have existing DB with the following structure:
I'm using EF fluent API to configure relationships between tables:
public GroupEntityConfiguration()
{
HasMany(x => x.Employees).WithRequired().HasForeignKey(x => x.GroupId).WillCascadeOnDelete(true);
}
public EmployeeEntityConfiguration()
{
HasOptional(x => x.InnerGroupMember).WithRequired();
}
With this configuration applied I can add new Employee, new InnerGroupMember or fetch data. The problem appears when I try to remove Employee. Then I get an exception:
The relationship could not be changed because one or more of the foreign-key properties is non-nullable. When a change is made to a relationship, the related foreign-key property is set to a null value. If the foreign-key does not support null values, a new relationship must be defined, the foreign-key property must be assigned another non-null value, or the unrelated object must be deleted.
As far as I understand above exception is connected with GroupId foreign key. Trying to fix it I'm adding following line to EmployeeEntityConfiguration:
HasKey(x => new { x.Id, x.GroupId});
But after adding it I get another exception which I believe is connected with InnerGroupMember object:
Invalid column name 'Guest_Id'. Invalid column name 'Guest_GroupId'.
If I comment out InnerGroupMember navigation property and remove it's configuration, Employee can be removed.
Could you please give me a hint what I'm doing wrong and how to configure entities to be able to perform all needed operations? Thanks!
I have an existing Group entity and I want to remove Employee from the Employees Group collection:
var group = groupRepository.Find(groupId);
group.RemoveEmployee(employeeId);
_unitOfWork.Save();
RemoveEmployee function inside Group entity looks like this:
public void RemoveEmployee(int employeeId)
{
var employee = Employees.Single(n => n.Id == employeeId);
Employees.Remove(employee);
}
That's why I get an exeption:
The relationship could not be changed because one or more of the foreign-key properties is non-nullable....
After reading this post I wanted to fix it adding HasKey(x => new { x.Id, x.GroupId}); function inside EmployeeEntityConfiguration what leads to the second exception:
Invalid column name 'Guest_Id'. Invalid column name 'Guest_GroupId'.
Actually I made this step (I mean adding HasKey function) without changing DB structure. To make it work, inside Employees table I have to create composite key - combination of Id and GroupId which is also a foreign key. This modification forces changes inside InnerGroupMembers table. DB structure looks now as following:
Now I'm able to remove Employee in a way I showed at the beginning.
Anyway I'm not going for this solution. They are different ways to achieve what I want. Here are some links:
Removing entity from a Related Collection
Delete Dependent Entities When Removed From EF Collection
The relationship could not be changed because one or more of the
foreign-key properties is non-nullable
For one-to-one relationships cascading delete is not enabled by default, even not for required relationships (as it is the case for required one-to-many relationships, that is: The WillCascadeOnDelete(true) in your one-to-many mapping is redundant). You must define cascading delete for a one-to-one relationship always explicitly:
HasOptional(x => x.InnerGroupMember).WithRequired().WillCascadeOnDelete(true);
When you delete an Employee now, the database will delete the related InnerGroupMember as well and the exception should disappear.

Entity Framework Error 3002 / 3003 - Inheritance / key mapping issue

I have a data model as follows:
A Customer has Products and Payment Methods. Each Product can be assigned any or all of the Customer's Payment Methods, with one set as default.
Foreign Keys are:
Customer.CustomerId => Product.CustomerId
Customer.CustomerId => PaymentMethod.CustomerId
Product.ProductId => ProductPaymentMethod.ProductId
PaymentMethod.PaymentMethodId => ProductPaymentMethod.PaymentMethodId
I want to customise this model for presentation purposes, Customer to have a collection of Payment Methods and a collection of Products. Products to have a collection of ProductPaymentMethods which inherit from PaymentMethod.
I deleted the association between PaymentMethod and ProductPaymentMethod, added an inheritence from PaymentMethod to ProductPaymentMethod and deleted PaymentMethodId from ProductPaymentMethod.
This is now my model:
When I save the model or build the project I get 2 errors:
Error 3002: Problem in mapping
fragments starting at line
226:Potential runtime violation of
table ProductPaymentMethod's keys
(ProductPaymentMethod.ProductPaymentMethodId):
Columns
(ProductPaymentMethod.ProductPaymentMethodId)
are mapped to EntitySet
PaymentMethods's properties
(PaymentMethods.ProductPaymentMethodId)
on the conceptual side but they do not
form the EntitySet's key properties
(PaymentMethods.PaymentMethodId).
and
Error 3003: Problem in mapping
fragments starting at line 226:All the
key properties
(PaymentMethods.PaymentMethodId) of
the EntitySet PaymentMethods must be
mapped to all the key properties
(ProductPaymentMethod.ProductPaymentMethodId)
of table ProductPaymentMethod.
What am I doing wrong?
EDIT: Having done some further Googling, I have found several solutions, most of which don't quite fit this scenario. Most talk about inheritance requiring a 1-1 not 1-many relationship. However, because of the Customer to Product 1-many relationship, the model requires a 1-many between PaymentMethod and ProfilePaymentMethod. Is it not possible to do what I am attempting?
My only answer to this so far is to have some manually created POCO classes for presentation and a Mapper class to turn my data entity into a presentation entity

Entity Framework Code First - Table Per Type Inheritance - Insertion Issue?

I'm having an issue inserting an instance of a subclass that inherits from a base class.
Consider the following code snippets from these POCOs:
public abstract class EntityBase<T>
{
private T _id;
[Key]
public T ID
{
// get and set details ommitted.
}
}
public abstract class PersonBase<T> : EntityBase<T>
{
// Details ommited.
}
public class Applicant : PersonBase<int>
{
// Details ommitted for brevity.
}
public class Employee : Applicant {}
Pretty standard inheritance right now. In our system, when an applicant finally becomes an employee, we collect extra data. If not hired, they remain an applicant with a limited set of information.
Now consider the fluent API that sets up the table-per-type inheritance model:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// Set up table per type object mapping for the Visitor Hierarchy.
modelBuilder.Entity<Employee>().ToTable("Employees");
}
So far, so good...
If I look at the database this creates, I have a table named Applicants with an Id column of type int, auto-incrementing ID and I have an Employees table with an ID field as the primary key (non auto incrementing).
Basically, the ID field in the Employees table is a foreign key to the Applicants table.
This is what I want. I don't want a record into the Employees table corresponding to the Applicants table until they actually become an Employee.
The problem comes when I try to insert an Employee which comes down to this code:
public void PersistCreationOf(T entity)
{
DataContextFactory.GetDataContext().Set(typeof(T)).Add(entity);
}
The problem: It inserts a brand new applicant and Employee. I hooked it up to the Sql Profiler and looked at both insert queries that come down.
I want to just insert the Employee record with the ID it already has (the foreign key from the Visitors table).
I understand by default it needs to this: Obviously if you create a subclass and insert it, it needs to insert into both tables.
My question is is possible to tell the Framework - the base table already has information - just insert into the child table?
Thanks in advance!
Aside from sending raw SQL commands to insert the Employee minus Applicant properties fragment into the Employees table I believe it's impossible. You can either update or insert an entity. What you want is basically to update the base part of the Employee (or do nothing if nothing changed) and insert the derived part which is not possible.
Imagine what an ORM does: It maps key identities in the database to object identities in memory. Even in memory you couldn't achieve what you want: If you have an object in memory which is a Applicant, it is always an applicant. You cannot magically "upgrade" it to an Employee. You would have to create a new object of type Employee, copy the properties of the Applicant into the base properties of your new Employee and then delete the Applicant. The result is a new object with a new object identity.
I think you have to follow the same procedure in EF. Your Employee will be a new entity with new rows in both Applicant and Employee table and you need to delete the old Applicant. If you have autogenerated keys it will be a new identity with a new ID. (If you hadn't autogenerated keys you could supply the old ID again after deleting the old Applicant, thus "faking" an unchanged identity.) This will of course create big potential trouble if you have references to the old applicant with FK constraints.
Perhaps inheritance is not optimal for this scenario to "upgrade" an applicant into an employee. An optional navigation property (1-to-0...1 relationship) inside of the Applicant which refers to another entity containing the additional properties which make the applicant an employee would solve the problem. This navigation property could be set or not, letting you distinguish between an applicant and applicant which is also an employee. And you would not need to delete and change the ID of the applicant when you make it an employee.
(As said, "I believe". Maybe there is a hidden way, I didn't see.)