I would like to add a record to a SQL Server table using the Entity Framework. My table's entity has foreign keys and so has navigational properties for those fields. When adding a new record/entity, how do I populate the foreign key fields since they don't appear as properties of the entity?
The easiest way is to do a query for the related entities and use the Navigation Properties:
i.e.
Product p = new Product{
ID = 5,
Name = "Bovril",
Category = ctx.Categories.First( c => c.ID == 5)
};
ctx.AddToProducts(p);
ctx.SaveChanges();
If you want to avoid the database query the easiest approach is probably to use a STUB entity i.e.
// this is a stub, a placeholder for the real entity
Category c = new Category {ID = 5};
// attach the stub to the context, similar to do a query
// but without talking to the DB
ctx.AttachTo("Categories", c);
Product p = new Product{
ID = 5,
Name = "Bovril",
Category = c
};
ctx.AddToProducts(p);
ctx.SaveChanges();
If you want more help on this stub technique check out this blog post on the topic.
Related
I am rather new to the Entity Framework, so I am probably overlooking something simple here.
In my controller class I am adding a new Category entity to the database, next I am using that entity as a property on a Course entity. When I save the Course entity, the Category is saved to the database AGAIN, while I was hoping the new Course would reference the Category that was already inserted.
The (simplified) controller code that saves the first Category:
// Create and save the category
Category category = new Category {Name = "Test category"};
category = context.Categories.Add(category);
context.SaveChanges(); // The category object now has a CategoryId (the pk of the record)
// Create and save the course
Course course = new Course {
FullDescription = "This is a new course",
Name = "My new course",
Category = category // Hoping this will have EF make a link to the just inserted category
};
context.Courses.Add(course);
context.SaveChanges(); // Saves the Course AND creates a **new** Category in the db
The problem seems to be that I call saveChanges() twice. What works is removing the first call to context.saveChanges(), BUT, this is not my actual code. In my application I use a repository pattern and adding a category is done by calling categoryRepository.AddCategory(Category category). And saving the Course is done in exactly the same way, by calling courseRepo.AddCourse(Course course) that also contains a call to saveChanges().
public Category AddCategory(Category category)
{
category = context.Categories.Add(category);
context.SaveChanges();
return category;
}
I don't want to remove the calls to saveChanges() in AddCourse() and AddCategory(), because I want these to be atomic operations.
I was hoping that returning the category and subsequently using the category as a property on a new Course would link that course to the category, but apparantly that is not the case. How do I link my Course to a category that is already present in the database?
I'm not sure how your data model is structured but you could do something like this.
course.CategoryId = category.CategoryId;
That way you map the actual foreign key in the relationship and it does the same thing.
Category category = new Category {Name = "Test category"};
Course course = new Course {
FullDescription = "This is a new course",
Name = "My new course",
Category = category
};
courseRepo.AddCourse(course);
You can use only AddCourse for adding both entities, if yours repositories has the same context. If each repository has their own context, you should attach category to the courseRepo context or load entity into it (but I suppose it not suitable for you because you have different repositories).
My ADO.Net Entity Data Model has a model called ABC below (modeled after a self-referencing table).
ABC Properties are
----------
ParentID
Child ID
ABC Navigation Properties are
----------
ParentCategory (refers to the parent category or the 0..1 side of the relationship)
SubCategories (refers to the children or the * side of the relationship, represents the navigation property for the children)
I want to select the children and grandchildren for a specific ParentID (i.e. not the top of the hierarchy ). How can I accomplish this. Can someone please propose an example. Thanks
I have tried the solution proposed below in vb, but it is only loading one level;
I am doing this in VB so apologies to C# programmers.
Protected Sub Button2_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Button2.Click
Dim ctx = New links2Entities
Dim query = From c In ctx.PBS.Include("SubCategory.SubCategory") Where (c.Parent_ID = 7)
For Each result As PB In query
Debug.WriteLine("ID: {0}", result.Child_ID)
Next
End Sub
If you need to select entity by its Id and eager load two levels of its children you need to do:
var query = context.ABC.Include("SubCategories.SubCategories")
.Where(e => e.Id == id);
In case of EF 4.1 it should be:
var query = context.ABS.Include(e => e.SubCategories.Select(s => s.SubCategories))
.Where(e => e.Id == id);
If you need to eager load all sub categories in any depth there is not way to tell it EF.
I am trying to achieve the following using Entity framework 4.0 and self-tracking entities:
1) The client application request a book form the server by providing an ISBN number
2) The server performs a query on its database to see if the book is already present
3a) If the book is in the database, it returns it.
3b) If the book is not in the database, it will query Amazon for info, extract the required attributes, create a new book, store it in the database, and return it to the client
Now, 3b) is where the problems are... I can't find any information on how I can create an entity object (a book) on the server side, add it to the context and store it in the database. I have tried all sorts of things:
public class BookBrowserService : IBookBrowserService {
public Book GetBook(string ISBN) {
using (var ctx = new BookBrowserModelContainer()) {
Book book = ctx.Books.Where(b => b.ISBN == ISBN).SingleOrDefault();
if (book == null) {
book = new Book();
book.ISBN = ISBN; // This is the key
book.Title = "This title would be retrieved from Amazon";
Author author = new Author();
author.Name = "The author's name would be retrieved from Amazon";
book.Authors.Add(author);
ctx.Books.AddObject(book);
ctx.SaveChanges(); // This one always throws an exception...
}
return book;
}
}
}
Could anyone tell me what I am doing wrong?
It looks like the problem is related to the EDMX model.
I have a Book entity and an Author entity, with a many-to-many relationship.
The Book entity's Key is ISBN, which is a string of Max length 13.
StoreGeneratedPattern is set to None.
The Author entity's Key is Id, which is a Guid.
StoreGeneratedPattern is Identity.
The exception message is:
"Cannot insert the value NULL into column 'Id', table 'BookBrowser.dbo.Authors'; column does not allow nulls. INSERT fails. The statement has been terminated. "
But since StoreGeneratedPattern is set to Identity, shouldn't an Id value be created automatically?
Thanks,
Peter
It looks that the problem was that I used a Guid as Key in combination with StoreGeneratedPattern = Identity.
When I set StoreGeneratedPattern to None and create my own Guid using Id = Guid.NewGuid(), the problem is gone.
Apparently, the SQL server cannot generate Guids...
you can use StoreGeneratedPattern=Identity, but generated sql script based on your edmx doesn`t contain newid() in describing primary key(GUID). you can do this manually in generated sql script. 'BookId uniqueidentifier NOT NULL
DEFAULT newid()'. So id value will create GUID automatically.
Let's say I have a Person class and an Order class, with foreign keys in the DB. The EF model will mark Person with a List of Orders and Order with a Person instance.
If I want to set the Person for the Order, do I really have to do it with an instance of Person?
Is there not a slimmed down way to do so, say with just a PersonID ?
To assign Person entity to a Order without loading Person entity, you have to do something like this:
var db = new OneToManyEntities();
var Order = new Order { OrderId = 100, OrderName = "Order name" };
Order. PersonReference.EntityKey = new EntityKey("OneToManyEntities.Person ","PersonID",10);
db.AddToOrders(Order);
db.SaveChanges();
Puzzled's answer is correct for EF v1. It's a pain. If you don't mind the extra query, you can set the property succinctly:
int id = 1;
Order.Person = context.Persons.Where(x => x.PersonID == id).FirstOrDefault();
Entity Framework v4 will have "FK Associations", which is a fancy term for directly-settable foreign keys.
Having some experience with Linq to SQL I'm trying out ADO Entity framework now. In Linq to SQL, I would create a Linq to SQL class, drag my tables across to build the data context. Then I'd instantiate the datacontext class and run some lambda against one of the properties in the datacontext class.
Now, with ADO entity framework I add the Entity Data Model class, and add the tables to the data model. My Entity Data Model class now has a bunch of ObjectQuery<> properties, one for each table I added.
Now what do I do with those properties? How do I call them? Anyone have code examples?
Sure. I have a long presentation on this.
As a simple answer to your question, here are some things you can do with the ObjectQuery<T> properties.
Return a list of objects:
IEnumerable<Customer> result = Context.Customers;
return result;
Return one object:
return Context.Customers.Where(c => c.Id == someId).First();
Project onto a presentation model:
return (from c in Customers
where c.Id == someId
select new CustomerPresentation
{
Id = c.Id,
Name = c.Name,
OrderCount = c.Orders.Count(),
PhoneNumbers = from p in c.PhoneNumbers
select new PhoneNumberPresentation
{
AreaCode = p.AreaCode,
// etc.
},
// etc.
}).First();