Entity Framework-Saving models with related tables - c#

So my question basically has to do with nested models or associated tables (not sure the correct term).
Specifically when TableA has an ICollection of TableB objects and TableB has an ICollection of TableA, how do I then save off my entire TableA model along with it's assocaited Table2 items.
For example:
User table with: string name, string address, ICollection < Orders >
Orders table with: OrderID, Total, ShipDate, ICollection < User >
So I have a User instance (UserA) which has the name and address set along with a collection of orders (Let's say Bob Dole, 1234 Main st, [567, $12.34, Oct 1; 999, $27.89, Nov 5;]).
How do I trigger the save method to save both Orders & the User?
My expectation would be "db.User.add(UserA); + db.SaveChanges();". I would expect this to save the User and upon seeing the Orders collection, save those as well.
However, previous developers did this:
User userB = db.User.Add(new User(userA.Name, userB.address)); //Why do we have to create a 2nd instance of a User object, that will hold the same information as userA?
foreach(Order order in userA.orders)
{
Order NewOrder = db.Orders.Add(order); //This now updates the Orders table with new info, which will be saved by 'db.SaveChanges()'
NewOrder.User.Add(userB); //How does this update the value in the Orders table with the userID? Isn't this updating the object about to go out of scope?
}
db.SaveChanges()
The only thing we can think, is the way they did it userB get's 'ID' assigned from the .Add command. But couldn't you simply say "userA = db.Users.Add(userA)" in order to update the instance with the ID provided upon database insert?

First of all, I think, you've got to change your schema.
There will be one-to-many relationship between User and Orders. One user can have multiple orders but one order can not belong to multiple users. i.e. Only Order table would have UserId.
Update
Further, No need to add Orders data separately. As there would available collection type in the User table's entity.
You need to just assign values to the User table's entity along with Orders field and do insert it only once.
The code would be somehow as below:
var userData = user;
var orderData = orderCollection;
userData will be single record and orderData could be multiple.
Now assign that data to User data model:
var userAndOrder = new User
{
Name = user.Name,
Address = user.Address,
Orders = orderCollection.Select(o => new Order
{
//assign order fields here
}).ToList();
};
Then save this data. It will save Orders data itself in the Order table against the UserId.
db.Add(userAndOrder);
db.SaveChanges();

Related

Outerjoin with a table of foreign keys in EF Data-first approach

I have a table Users which contain user information. I have a table Products which contain product information. I have a table called UserProduct which acts as a junction table and whose fields are UserId and ProductId. I am using a Entity Framework database first approach.
I want to outerjoin using Linq to find the following data.
All Users in the Users table.
All Users who have bought a particular product in terms of a Boolean called isPurchased.
My thinking was to left outer join table User with UserProduct and get all users and whether they have a product something like this.
var result = from a in Users
join b in UserProduct(Not available through EF) on a.Id equals b.prodId into group1
from g1 in group1.DefaultIfEmpty()
select new
{
id = g1.Id,
isPurchased = g1.prodId != null
}.ToList();
However in EF mapping, the object UserProduct is not created and so I cannot use it directly in my Linq query? So how do I go about this? Is there a way I can use linq to join tables with the actual table name(UserProduct) instead of joining entities?
Assuming Users contains a property List<Products> products to represent the junction information, and a variable boughtProductId to represent the particular product:
var result = from u in Users
let isPurchased = u.products.Any(p => p.Id == boughtProductId)
select new {
id = isPurchased ? boughtProductId : null,
isPurchased
}.ToList();

Adding multiple Products into same Order table. (M-M relationship)

Doing a shop project. Upon checkout, I create a list of all added product from cart and put it inside Order.Products(M-M relationship):
List<Product> productList = Cart.Select(item => db.Products.SingleOrDefault(x => x.Id == item)).ToList();
var addOrder = new Order
{
Id = Guid.NewGuid(),
UserId = userId,
OrderDate = DateTime.Now,
Products = productList
};
db.Orders.Add(addOrder);
db.SaveChanges();
I debugged my code to make sure the productsList had the right amount.
But after I added it, I only had one of each added products were added in my db. For e.g. if I have 3x cars, 4x books and 2x boat, then I just get one of each into M-M table, meaning total 3 products, even though I had total 9 in productList.
This is how I set up my m-m relationship.
create table Product_Order (
ProductId uniqueidentifier foreign key references [Product](ID) not null,
OrderId uniqueidentifier foreign key references [Order](Id) not null
)
Btw, is it possible to add additional column into Product_Order so called AmountProduct, and set amount value instead making many rows of same products/order? If possible, how do I set amount value inside var addOrder = new Order{? That way would probably be much more effective.

How do I insert a record with the key of the previous record in one call?

In my database, I have a table called Department that columns named DepartmentID (PK) and SubdepartmentOfID (FK). SubdepartmentOfID is constrained as a FK to DepartmentID in order to basically create a hierarchical type relationship.
What I'm trying to do in Entity Framework 6 is to create a default subdepartment that has the same name as the department, but in order to do so, I need to be able to set the SubdepartmentOfID before inserting it though my context, right? Currently, I'm using this logic:
Create the entity, insert it, save it (this ends up populating the DepartmentID key in the entity).
Create another entity for the subdepartment and set its SubdepartmentOfID property equal to that of the previously saved entity, save it
I feel like this could be done in one call. Can it?
This answer assumes the following:
You're using database first (using the designer) as opposed to code first
You have a table named Department with the following columns
DepartmentID
SubDepartmentID
DepartmentName
I think you can do this.
var department = new Department
{
DepartmentName = "D1"
};
var subDepartment = new Department
{
DepartmentName = "D1"
};
department.Department = subDepartment;
context.Departments.Add(department);
context.SaveChanges();
Entity framework will now take care of the autogenerated IDs and associate the sub department to the department.

Including a second query in Entity Framework LINQ Query

I've got a table "Houses" and "Cats", which contains the columns "Id" and "HouseName" and "Id" and "CatName".
Now I got a table "HouseCatAssignments", where I store the relations between the Cats and the Houses (the Cat can live in more than one house and one house can store more than one cat).
This table looks like:
Id, CatId, HouseId
"CatId" is bound to Cats.Id and HouseId is bound to Houses.Id.
Now I want to display the Table "House" in a datagrid that also contains a field for "CatCount" - a counter for the value of how many cats are living in this house.
How should I now query my tables so I have all the values of "Houses" and an additional Column that contains the Cat-Count for the specific house?
For Entity Framework it should have automatically added navigation properties that allow you to do the following query:
var housesWithCount = context.Houses
.Select( h=> new
{
Id = h.Id,
HouseName = h.HouseName,
CatCount = h.Cats.Count()
});

Table with 2 foreign keys entity framework

I have a table which consists of 2 foreign keys. And those are only elements of the table. The table is meant to create association between 2 other tables. For example: The table is Users_Products, and the only 2 columns are UserId and ProductID, both foreign keys. When I generated the EF object from database it didn't create Users_Products object, it only automatically created navigation properties. Now how can I insert data in my Users_Products table using EF?
You can get some user object and add product into its navigation property.
User user = context.Users.Where(u => u.Id == 1);
Product product = context.Products.Where(p => p.Id == 1);
user.Products.Add(product);
context.SaveChanges();
For code examples that show how to work with many-to-many relationships in EF see the Working with Many-to-Many Relationships section in
The Entity Framework 4.0 and ASP.NET – Getting Started Part 5.
That is EF 4.0 / Database First; for an example using the DbContext API, see Adding Course Assignments to the Instructor Edit Page in Updating Related Data with the Entity Framework in an ASP.NET MVC Application (6 of 10).
using ( var ctx = new ...)
{
var user = new User();
var product = new Product();
user.Products.Add(product);
ctx.Users.AddObject(user);
ctx.SaveChanges();
}
If you want to create relation (insert record to User_Products table) you just need to use navigation property either on User or Product:
user.Products.Add(product);
or
product.Users.Add(user);
That means you must have navigation property on at least one side to be able to create the relation. If you have loaded entities from the current contest you can use the approach described by #Pavel.
If you don't have loaded entities or if you don't want to do two queries to the database just to make a relation you can use this workaround:
// Make dummy objects for records existing in your database
var user = new User() { Id = 1 };
var product = new Product() { Id = 1 };
// Ensure that your context knows instances and does not track them as new or modified
context.Users.Attach(user);
context.Products.Attach(product);
// Again make relation and save changes
user.Products.Add(product);
ctx.SaveChanges();

Categories