Entity Framework - add to join with only foreign key values - entity-framework

OK, I have 3 tables, call them:
Person
PersonID
Name
Store
StoreID
Name
PersonStore
PersonID
StoreID
Now, I have a form which allows you to add stores to a person. However, I am getting the store ID back from the form. I don't really want to do a query to get the store object from Entity Framework. I just want to add to the table using the StoreID and the Person object which I have.

By default in EF this join table won't appear as an entity instead you'll get a many to many relationship which will show up as two navigation properties
i.e.
Person.Stores
Store.People
If you want to build a many to many relationship without retrieving the entities then attaching stub entities is the best way.
var person = // you already have the person
var store = new Store{StoreID = 5} // you know the storeID
ctx.AttachTo("Stores", store);
ctx.AttachTo("People", person); // assuming the person isn't already attached
person.Stores.Add(store);
ctx.SaveChanges();
The only problem with this code is it will fail if the relationship already exists, so you need to be sure you are creating a new relationship
For more on using Stub entities like this check out my post.
Hope this helps.
Alex
Edit from OP:
Since I am using EF4, I used the following code to remove the string from the attach (thanks to tip 13 from the link).
var person = // you already have the person
var store = new Store{StoreID = 5} // you know the storeID
ctx.Stores.Attach(store);
person.Stores.Add(store);
ctx.SaveChanges();

Related

Entity Framework 6 - Form relationship using object which doesn't exist in the DB yet

Suppose a Company has Employees. Company 'Solutions' has Employee 'James'.
These entities are both saved in the DB, and their relationship is expressed through a foreign key.
At the application level, the Employee class has a Company object property, to define the relationship.
Suppose a new company 'Better Solutions' is created, which doesn't exist in the DB yet, and James now moves to this company.
How do I tell EF to handle this? Currently I:
Save the new company 'Better Solutions' (object created with a GUID ID) to the DB:
db.Companies.Add(newCompany);
Change the Company property on Jame's instance:
james.Company = newCompany;
Tell EF that a property on James's instance has changed and needs updating:
db.Employees.Attach(james);
db.Entry(james).State = System.Data.Entity.EntityState.Modified;
But when this happens, the newCompany object doesn't have its new database ID yet (even though it's been added to the database, the object still holds the GUID ID), so when saving EF tries to do this:
UPDATE [dbo].[Employee]
SET [CompanyID] = SomeGUID,
WHERE ([EmployeeID] = JamesID)
Which of course throws an exception because no CompanyID matches that GUID:
The UPDATE statement conflicted with the FOREIGN KEY constraint
In this scenario, do I need to first push the newCompany object to the DB, then retrieve it from the DB (to get the new ID), then set this retrieved object as James's Company property?
Or does EF have a cleaner way of taking care of all this?
try to do like below. Save company first then assign it to james that will update existing employee.
db.Companies.Add(newCompany);
db.SaveChanges();
james.Company = newCompany;
db.SaveChanges();

Attaching an related entity to new entity, without retrieving from database

I've just started working with Web API this week, and I'm struggling with something which I think should be quite simple, but haven't been able to find the answer for yet. Perhaps I'm searching using the wrong terms.
One of the calls to the API passes through a GUID. I need to create a new entity (using Entity Framework) and set one of the relations to this newly passed in GUID. This GUID is the ID of a different entity in the database.
I'm struggling to attach the entity via the relation without fetching the whole entity too.
For example,
public void DoWork(IList<Guid> userGuids)
{
Order order = new Order() // This is an entity
{
CreateDate = DateTime.Now,
CreatedBy = "Me",
Items = (from i in this.Model.Items
where i.Id == userGuid
select i).ToList<Item>();
}
Model.Orders.Add(order);
Model.SaveAll();
}
In the above, I have to do a database call to attach the Item entities to the Order. Is there not a way around this? Seems very redundant to retrieve the whole entity objects when I only require their IDs (which I already have anyway!)!
One solution is stub entities as asked here: Create new EF object with foreign key reference without loading whole rereference object
Link to the source blog referenced: http://blogs.msdn.com/b/alexj/archive/2009/06/19/tip-26-how-to-avoid-database-queries-using-stub-entities.aspx
Snip from the blog - to be applied to your situation:
Category category = new Category { ID = 5};
ctx.AttachTo(“Categories”,category);
Product product = new Product {
Name = “Bovril”,
Category = category
};
ctx.AddToProducts(product);
ctx.SaveChanges();
This way (in the example) the Product is saved without ever loading the Category object.

Use inserted record's identity without commiting

Let's say I have two tables: table Category and table Book
I would like to add a Category, then use its ID for inserting a book (which has a CategoryId field pointing to the table Category).
To get this info, I now commit my changes after inserting the category as it is not provided otherwise.
Is there a way to point to this category when inserting my book without commiting after inserting the category?
Thanks in advance
If the ID is generated by the database, then no, you can't get it until it is committed
It sounds like you have a FK relationship setup. If that's the case, if you associate the Category and Book entities together - EF should be create the necessary FK's.
For example:
var Category = new Category();
Book.Category = Category;
context.Books.Add(Book);
context.SaveChanges();
Would create a book, and a category and depending on how your mapping is setup the proper fields should be set. Can you post your model if this is not the case?

Select base class in Entity Framework

Suppose I have
table Person
table Employee, which inherits Person.
I want to get a list of Person, regardless if this Person is Employee or not. How do you get entity framework to do that without joining the Employee table? C# is what I'm using. Thanks.
You need to make sure that you don't implicitly use any information from Employee.
If you do this:
var people = Context.People.ToList();
... Then me Entity Framework will initialize new instances of type Employee for those people who happen to be employees. This is because when you store an Employee in the database, you generally expect to get an Employee back when you select the same item.
Nor, for that matter, can you tell the Entity Framework to give you a Person when the stored value is an Employee. The Entity Framework will never give you back an incorrect entity type.
However, if you do just want to read the one table, there is a way to do that: Select the data from Person into a non-entity types, such as an anonymous type:
var people = Context.People.Select(p => new { Name = p.Name }).ToList();

Adding & Removing Associations - Entity Framework

I'm trying to get to grips with EF this week and I'm going ok so far but I've just hit my first major snag. I have a table of items and a table of categories. Each item can be 'tagged' with many categories so I created a link table. Two columns, one the primary ID of the item, the other the primary ID of the category. I added some data manually to the DB and I can query it all fine through EF in my code.
Now I want to 'tag' a new item with one of the existing categories. I have the category ID to add and the ID of the Item. I load both as entities using linq and then try the following.
int categoryToAddId = Convert.ToInt32(ddlCategoriesRemaining.SelectedValue);
var categoryToAdd = db.CollectionCategorySet.First(x => x.ID == categoryToAddId);
currentCollectionItem.Categories.Add(categoryToAdd);
db.SaveChanges();
But I get "Unable to update the EntitySet 'collectionItemCategories' because it has a DefiningQuery and no element exists in the element to support the current operation."
Have I missed something? Is this not the right way to do it? I try the same thing for removing and no luck there either.
I think I have managed to answer this one myself. After alot of digging around it turns out that the Entity Framework (as it comes in VS2008 SP1) doesn't actually support many to many relationships very well. The framework does create a list of objects from another object through the relationship which is very nice but when it comes to adding and removing the relationships this can't be done very easily. You need to write your own stored procedures to do this and then register them with Entity Framework using the Function Import route.
There is also a further problem with this route in that function imports that don't return anything such as adding a many to many relationship don't get added to the object context. So when your writing code you can't just use them as you would expect.
For now I'm going to simply stick to executing these procedures in the old fashioned way using executenonquery(). Apparently better support for this is supposed to arrive in VS2010.
If anyone feels I have got my facts wrong please feel free to put me right.
After you have created your Item object, you need to set the Item object to the Category object on the Item's Categories property. If you are adding a new Item object, do something like this:
Using (YourContext ctx = new YourContext())
{
//Create new Item object
Item oItem = new Item();
//Generate new Guid for Item object (sample)
oItem.ID = new Guid();
//Assign a new Title for Item object (sample)
oItem.Title = "Some Title";
//Get the CategoryID to apply to the new Item from a DropDownList
int categoryToAddId = Convert.ToInt32(ddlCategoriesRemaining.SelectedValue);
//Instantiate a Category object where Category equals categoryToAddId
var oCategory = db.CategorySet.First(x => x.ID == categoryToAddId);
//Set Item object's Categories property to the Category object
oItem.Categories = oCategory;
//Add new Item object to db context for saving
ctx.AddtoItemSet(oItem);
//Save to Database
ctx.SaveChanges();
}
Have you put foreign keys on both columns in your link table to the item and the category or defined the relationship as many to many in the Mapping Details?