Breezejs EF BeforeSaveEntities editting savemap - entity-framework

I'm trying to add some logic into the BeforeSaveEntities method.
On the client we can add a parent record and a number of child records before hitting save.
Our parent record has two fields which can be chosen by the user and are a sort of unique identifier (but not the id). The child record also has some unique identifiers and a total field. The classes look something like this:
public class Parent
{
public int Id { get; set; }
public int Ref1 { get; set; }
public int Ref2 { get; set; }
public virtual ICollection<Child> Children { get; set; }
}
public class Child
{
public int Id { get; set; }
public int Ref1 { get; set; }
public int Ref2 { get; set; }
public int Total { get; set; }
public int ParentId { get; set; }
[ForeignKey("ParentId")]
public Parent Parent { get; set; }
}
In the BeforeSaveEntities I'm trying to check if a parent record with the Ref1 and Ref2 fields the same as the added entity using a second context.
If a parent record exists, I remove it from the savemap to prevent it from being re-added (this seems to work).
I then look at the child records being added (again by querying a second context), and what I'm trying to do is allow the new record to be added by leaving them in the savemap where they don't exist (but updating the parentid to link them to the existing parent record).
If a child record already exists, I want to increment the total of the existing record by the value in the added one in the savemap.
I've tried a couple of ways, but can't seem to get it working. It always seems to result in all child entries for the parent getting added again, even if there is only one new child entity in the savemap.
Apologies for the contrived classes, but hopefully this gives enough info to convey what I'm trying to do.

Related

Entity Framework: Mapping many-to-many

During my project in which I make some sort of webshop, I've came across a problem with my .NET backend where I use Entity Framework Code First with Fluent API.
In my frontend, Orders can be made and are passed to my backend where they end up as a Order object (code below). This Order contains a User and a Dictionary where Items and their ordered quantities are stored. My current goal is to store those Orders in my database to retrieve an Order history.
My understanding is that by itself, EF can't map a Dictionary. Being a student and having done mostly frontend, I don't really know how to tackle this.
I've tried converting that Dictionary to a List of ItemWrappers (containing both the Item and the amount) and making 2 tables: Order (OrderId, UserId) and OrderItem (OrderId, ItemId, Amount). This converts the Many-to-Many (Users to Items and Order is derived from the relation attribute) to a One-to-Many (Order to OrderItem).
I understand this from a purely database perspective. I could have managed if I were to write all the queries myself, but given that EF adds some abstraction to that, I am a bit lost. How do you suggest I do this?
The code is simplified to only show the class structure. Id is always generated on add and is used as primary key.
public class User {
public int Id { get; set; }
public string Name { get; set; }
}
public class Item {
public int Id { get; set; }
public string Name { get; set; }
}
public class Order {
public IList<OrderItemWrapper> ItemsList { get; set; }
//Either one of these 2
public Dictionary<Item, int> Items { get; set; }
public User User { get; set; }
public int Id { get; set; }
}
public class OrderItemWrapper {
public Item Item { get; set; }//Will use ItemId as key
public int Amount { get; set; }
}
Could you please go through my explanation for many-to-many relationship here.
Is the following tree of SchoolContext correct?

Entity Framework - Add an item to a list more than once

I am creating an Entity Framwork Code First app and am running into a problem when trying to add an entity to a list more than once.
I have the following two classes, which reference each other for a many-to-many relationship.
public class Order
{
public virtual List<OrderItem> OrderItems { get; set; }
}
public class OrderItem
{
public virtual List<Order> Orders{ get; set; }
}
This creates a the following three tables in my database:
Orders
- OrderId (PK, int)
.
OrderItems
- OrderItemId (PK, int)
.
OrderOrderItems
- Order_OrderId (PK,FK,int)
- OrderItem_OrderItemId (PK,FK,int)
In code, I wish to do the following:
private void AddOrderItemsTest
{
OrderItem orderItem = GetOrderItem(); // gets an existing order item from the DB
var order = new Order();
order.OrderItems.Add(orderItem);
order.OrderItems.Add(orderItem); // add the order item to the list a second time
context.Orders.Add(order);
}
When this gets persisted to the database, only a single orderItem entity is added to the list. We see in the table OrderOrderItems that OrderItem_OrderItemId is a PK and therefore must be unique. This means that EF has designed the tables in a way that won't allow more than one orderItem of the same type to be added to the list more than once.
Is there a Data Annotation that I can add to tell EF to allow me to add more than one item of the same type to the list?
I believe that it is not correct way of handling item count (of same item) in your order. Do you really want 10000s duplicated entries loaded into your OrderItems collection? I guess not.
You will need different primary key on OrderOrderItems table, hence suggest to introduce new entity that will contain OrderItem amount per Order:
public class OrderItemDetails
{
public int OrderItemDetailsId { get; set; }
public int OrderId { get; set; }
public int OrderItemId { get; set; }
public int Amount{ get; set; }
public virtual Order Order { get; set; }
public virtual OrderItem OrderItem { get; set; }
}
public class Order
{
public virtual List<OrderItemDetails> OrderItemDetails { get; set; }
}
public class OrderItem
{
public virtual List<OrderItemDetails> OrderItemDetails { get; set; }
}
And if you not happy with introducing Amount and still want to have duplicated entries per each item instance that will be absolutely fine because primary key of your many to many relation will be not combination of OrderId and OrderItemId but OrderItemDetailsId.

Entity Framework with Proxy Creation and Lazy Loading disabled is still loading child objects

I'm having some issues with the Entity Framework using POCOs and I hope someone can tell me at a high level if the behaviour I'm seeing is expected or I need to dig deeper into why it's happening.
I have a class Customer and another CustomerType, so Customer has a property Type (of type CustomerType indicating the type) and CustomerType has property Customers which is a collection of Customers (All Customers that have that type) So these are basically the Navigation properties on both ends of an association, resulting in POCO code something like:
public partial class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public int TypeId { get; set; }
public CustomerType Type { get; set; }
}
public partial class CustomerType
{
public CustomerType()
{
this.Customers = new HashSet<CustomerType>();
}
public int Id { get; set; }
public string TypeName { get; set; }
public virtual ICollection<Customer> Customers { get; set; }
}
I have turned off Proxy creation and LazyLoading (i.e. both DbContext.Configuration.ProxyCreationEnabled=false and DbContext.Configuration.LazyLoadingEnabled=false) because they make Serialization a pain.
As expected when I get instances from the Customer set, the Type property on them is null by default.
But if I get instances from the Customer set with a .Include("Type") not only is it loading the Type properties, but it's also loading the children - i.e. the collection of Customers on each of these.
Is this expected?
It is semi expected. The Include extension affects the SQL that is run. Those CustomerTypes that ARE loaded (by virtue of being included in the Customer query) will be built into the object tree according to the CustomerType.ParentId column.
So if by some fluke both a parent and a child is loaded in the same query, the child will be stuffed into the parent.

Entity Framework asp.net MVC foreign key

I am trying to code the following in code first... since I am just begining I am not able to.. please help.. thanks in advance
1. Student: Student will have student ID, First Name, Last Name
Student should belong to one class and one section(basically one to one relationship with each entity)
2. Classes: Class will have ClassId, Name
Class should have collection of students and collection of sections(basically many to many relationship with each entity)
3. Sections: Section will have SectionID, Name
Section should belong to one class and should have collection of students(basically one to one relation with class and one to many relation with Students)
Below is the code for the same
Students.cs
public class Students
{
public int StudentsId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string UserName { get; set; }
public decimal Grade { get; set; }
public int ClassesId { get; set; }
public Classes Classes { get; set; }
public int SectionsId { get; set; }
public Sections Sections { get; set; }
}
Classes.cs
public class Classes
{
public int ClassesId { get; set; }
public string Name { get; set; }
public ICollection<Sections> Sections { get; set; }
}
Sections.cs
public class Sections
{
public int SectionsId { get; set; }
public string Name { get; set; }
public int ClassesId { get; set; }
public Classes Classes { get; set; }
public ICollection<Students> Students { get; set; }
}
If I do this I get error saying:
Introducing FOREIGN KEY constraint
'FK_dbo.Sections_dbo.Classes_ClassesId' on table 'Sections' may cause
cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON
UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
I know I can get rid of this error using fluent APIs and telling not to cascade on delete, but I don't want to do that. Is there any other solution to this?? Please help
With your current model, no, there is no other way than disabling casdading delete for some of the relationships.
All your relationships are required, that means that if a class is deleted you delete the sections and the students of that class (Classes has a not exposed collection of students due to the required navigation property Classes in Students). But if the sections are deleted the students of that sections are deleted as well - and that's the second delete path to Students.
I don't know the exact meaning of your model but to me it sounds strange to delete all students of a class if the class gets deleted. Does a student always must have a class or couldn't he temporarily be without class assignment (and section assignment as well)? Maybe the student has a holiday semester for half a year and doesn't participate in any class?
In that case you could make the relationships of Students optional. Just declare the foreign key properties as nullable:
public class Students
{
//...
public int? ClassesId { get; set; }
public Classes Classes { get; set; }
public int? SectionsId { get; set; }
public Sections Sections { get; set; }
}
This would fix your problem of multiple cascading delete paths in the Students class because by default optional relationships don't have cascading delete enabled. The relationship between Classes and Sections is still required, so deleting a class will delete all sections belonging to the class as well, but it won't delete the students anymore.

EF CTP4 Missing columns in generated table

I'm having an issue that i just can't seem to figure out. Lets say I have 2 Entities defined in my domain; Person and Document. Below is the definition for Document :
public class Document
{
public int Id { get; set; }
[Required]
[StringLength(255)]
public string Title { get; set; }
public DateTime Date { get; set; }
public virtual Person Owner{ get; set; }
public virtual Person AssignedTo { get; set; }
}
Now, when EF CTP4 creates the SQL table on initialize, there is only one field mapping to a Person.Id being Owner_id. Whatever i try, the field for AssignedTo is never created.
Anything that could solve this?
Regards,
avsomeren
Your code perfectly created the desired schema in the database for me:
If you don't get this schema in you DB then my guess is that something is not right with the rest of your object model. Could you post your full object model please?
Another Solution:
While your current Document class will give you the desired results, but you can still take advantage of the Conventions for Code First and explicitly specify the FKs for your navigation properties:
public class Document
{
public int Id { get; set; }
[Required][StringLength(255)]
public string Title { get; set; }
public DateTime Date { get; set; }
public int OwnerID { get; set; }
public int AssignedToID { get; set; }
public virtual Person Owner { get; set; }
public virtual Person AssignedTo { get; set; }
}
Code First will now infer that any property named <navigation property name><primary key property name> (e.g. OwnerID), with the same data type as the primary key (int), represents a foreign key for the relationship.
This essentially results to the same DB schema plus you have the FKs on your Document object as well as navigation properties which gives you ultimate flexibility to work with your model.