Add a new Item in connected scenario, Entity framework - c#

Is it possible to add an entity in connected scenario in entity framework. I can update a data, but for add and delete, it does not work in connected mode.
md.Configuration.AutoDetectChangesEnabled = true;
var studentList = md.MyStudent.ToList<Student>();
studentList.Add(new Student { Stdname = "nm" });
md.SaveChanges();
the new item ("nm") wont be added!!!
EDITED
Why Does this work , an update operation and Add does not work, what is the difference?
the database will be updated
Student studentToUpdate = studentList.Where(s => s.Stdname == "stdname1").FirstOrDefault<Student>();
studentToUpdate.Stdname = "Edited stdname3";

Your code doesn't work because your ToList<Student>() returns a new list unrelated to your context. This is similar to the following code:
IList<Student> studentList = new List<Student>();
studentList.Add(new Student { Stdname = "nm" });
Your context from the entity framework don't care if you have a list somewhere in your program and add an object to it.
Editing existing objects in your list works because they were loaded from the context, therefore they are "registered" in the context.
If you want to add a new object you have to add it to md.MyStudent so the context sees that a new object should be added.

Try to use the md.MyStudent.Add() method.
A bit of explanation
EF has a change tracking mechanism so that it can automatically persist the changes you make to your entities. However, EF has to know about your object/entity in order to be able to detect the changes.
In your second example EF knows about the student entity because it was created by the framework, you applied the Where() extension method on a DbSet instance which is part of the EF context.
In your first example you also retrieved the entities from a DbSet, however this time you applied the ToList() extension method, which creates a new List<Student> instance containing all the students stored in your database, but EF doesn't have a reference to that list, only it knows about the entities in the list. As a result, if you add/remove items from that list EF won't know about your changes. You could still make changes to the entities in the list and get the modifications saved to the database.

Related

My Stack is losing its value when I redirect to another controller

I have tried this using a List and it retains the value fine, but when i change it to a stack the value is lost. I have been stepping through but I can't understand why its gone.
​
public ActionResult AddToOrder()
{
//Get logged in student from db
var student = _db.Students.Find(User.Identity.GetUserId());
//Create a new Order
var order = new Order();
//add all elements from Student collection to Order collection
foreach (var app in student.Applications)
{
order.Applications.Add(app);
}
//assign order FK
order.StudentId = User.Identity.GetUserId();
//Push the order to the students Stack collection
student.Orders.Push(order); //(When the Student implements a List collection the value
//passes to the Stripe controller with no problems)
//add order to db & save changes
_db.Orders.Add(order);
_db.SaveChanges();
//redirect to stripe controller
return RedirectToAction("Create", "Stripe");
}
//STRIPE CONTROLLER
public ActionResult Create(string stripeToken)
{
var student = _db.Students.Find(User.Identity.GetUserId());
student.Orders.Count // = 0 with Stack
// = 1 with List
}
The only thing I change is Stack to List in the Student entity and push to add. Anybody any ideas whats going on?
I guess I could achieve what I want (LIFO) by using a list in this way. I would still like to know what's going on with my stack though.
myList.Insert(0, order) - - - my List.First()
Student is an Entity Framework entity - an object representation of a database table. Its Orders property represents a relationship to another table. When you add order objects to a Student's Orders property, Entity Framework does a ton of stuff under the hood to make sure that all of the object data is correctly written to the database as table data, with all of the proper foreign keys and such, when you call SaveChanges. Same thing when you call Students.Find: There's a lot of stuff going on to translate your code to a SQL query, run it, then turn the resulting SQL table data into a convenient Student object.
Entity Framework does all of that automatically, but in order for it to work, entity classes like Student need to be defined in a particular way such that EF knows how to handle them. To put it succinctly: properties like Orders that represent relationships to another table need to be Lists. When you redefine Student.Orders to be a Stack, the Entity Framework machinery breaks, and EF can no longer use Orders to work with that portion of the database.
When your app redirects from one controller to another, the orders data is not retained in memory in the app, only in the database. When the target controller loads, your code is trying to load the data from the database that the previous controller was supposed to have saved there. One of two things is happening:
Your change to use Stack broke the Students entity such that the data doesn't get saved to the database at all, OR
Entity Framework can manage to handle Stack well enough to save the data, but not load it.
I'm not sure which is happening with this particular change, but either one is undesirable.
Orders needs to be a List. If you need to preserve some kind of ordering to the list, that needs to be explicit within the data model so that it ends up in the database. Maybe your Order class needs a LineNumber property or something similar. If you do something like that, keep in mind that both the code and the database have to be updated. Search for "Entity Framework migrations" for information about that, and ask a separate question if you get stuck on it.

Is there a way to automatically create CRUD for EF Model (DB First currently)

I am creating a WPF app and I have an existing DB that I would like to use and NOT recreate. I will if I have to, but I would rather not. The DB Is sqlite and when I add it to my data later and create a DataModel based on the DB, I get the model and the DB Context, however there are no methods created for CRUD or for instance .ToList() so I can return all of the items on the table.
Do I need to create all of these manually or is there a way to do it like the way that MVC can scaffold?
I am using VS 2017, WPF, EF6 and Sqlite installed with Nu-Get
To answer the question in the title.
No.
There is no click-a-button method of scaffolding out UI like you get with MVC.
If you just deal with a table at a time then you could build a generic repository that returns a List for a given table. That won't save you much coding, but you could do it.
If you made that return an iQueryable rather than just a List then you could "chain" such a query. Linq queries aren't turned into SQL until you force iteration and you can base one on another adding criteria, what to select etc etc for flexibility.
In the body of your post you ask about methods to read and write data. This seems to be almost totally unrelated from the other question because it's data access rather than UI.
"there are no methods created for CRUD or for instance .ToList() so I can return all of the items on the table."
There are methods available in the form of LINQ extension methods.
ToList() is one of these, except it is usual to use async await and ToListAsync.
Where and Select are other extension methods.
You would be writing any model layer that exposed the results of those though.
I'm not clear whether you are just unaware of linq or what, but here's an example query.
var customers = await (from c in db.Customers
orderby c.CustomerName
select c)
.Include(x => x.Orders) //.Include("Orders") alternate syntax
.ToListAsync();
EF uses "lazy loading" of related entities, that Include makes it read the Orders for each customer.
Entity Framework is an Object Relational Mapper
Which means it will Map your C# objects to Tables.
Whenever you are creating a model from bd it will create a Context Class which will in inherit the DbContext. in this class you will find all the tables in DbSet<Tablename> Tablename{get; set;}. Basically, this list contains will the rows. the operation performed on this list will affect the DB on SaveChange method.
Example for CURD
public DbSet<Student> Students { get; set; }
//Create
using (var context = new YourDataContext()) {
var std = new Student()
{
Name = "Aviansh"
};
context.Students.Add(std);
context.SaveChanges();
}//Basically saving it will add a row in student table with name field as avinash
//Delete
using (var context = new YourDataContext()) {
var CurrentStudent=context.Students.FirstOrDefault(x=>x.Name=="Avinash")
CurrentStudent.context.Students.Remove(CurrentStudent);
context.SaveChanges();
}
Note: on SaveChanges the change will reflect on Db

Deleting child items with EF Core

I have looked at several similar questions on deleting items from child collections in EF Core, and most do not have an accepted or answer relevant for EF Core:
https://stackoverflow.com/a/51349007
https://stackoverflow.com/a/49679247
I have a class called "Albums" and a property on it called "Musicians".
When I load Albums from the database with EF, I include the Musicians property so that the collection is already tracked by EF. If I add an item to the Musicians list and save changes on the Album entity, I notice it is added to the junction table for Musicians and Albums, and this works great. For deletes, this does not seem to have an effect.
Example:
var albums = repository.LoadAlbumsWithMusicians();
var musicians = CreateNewMusiciansForAlbumOne();
var test = albums.First().Musicians;
test.Clear();
test.AddRange(musicians);
With this code, if a composite primary key (MusicianId, MusicianType, and AlbumId) for a musician matches one which EF already knows about, even if it is actually a different object, it will do nothing as it knows this relationship already exists. That's what I expect.
If the primary key does not match an existing one then it will be treated as a new object in the collection and a new row is added to the database. That's also what I expect.
However, I can't seem to do anything that will make EF recognize that the items which were previously in the collection [and have been removed] should be deleted. In EF6, I simply used .Clear() and .AddRange() to handle these relationships, and EF handled the inserts and deletes for child relationships. Without explicitly removing these objects from the context as in this suggested answer, https://stackoverflow.com/a/49679247, how can I ensure these deleted child items are removed from the database?
Using the example below lets say our "selectedAppender" contains a record by ID and all junction table data. In order to add items and remove items from that junction table all we need to do is account for them in a separate object (delete and add object).
Once we have a list of items to delete it's as simple as calling the "remove" method.
Let me know if this isn't clear enough. Hopefully it helps.
file_appender selectedAppender = context.file_appender.Find(dto.Id);
int[] ids = dto.Loggers.Where(x => !x.Selected).Select(x => x.Id).ToArray();
var loggers_to_delete = selectedAppender.logger.Where(x => ids.Contains(x.id));
loggers_to_delete.ToList().ForEach(x =>
{
selectedAppender.logger.Remove(x);
});
ids = dto.Loggers.Where(x => x.Selected).Select(x => x.Id).ToArray();
var loggers_to_add = context.logger.Where(x => ids.Contains(x.id));
loggers_to_add.ToList().ForEach(x =>
{
selectedAppender.logger.Add(x);
});
One downside to linq is you have to approach these types of problems iteratively. There is no way I know of to do a bulk delete. If you know of a way and can improve on it please share it.

An object with the same key already exists in the ObjectStateManager

I have a scenario that could not find the solution for it and need some help
How can I achieve this,
I’d like to get current record for the client modify it and instead of update I’d like to add the new record to table for historical change information
client c = new client();
using (DBEntities db = new DBEntities())
{
// get current records in the client table for client
IQueryable<client> co = from p in db.client where p.CUS_NUMBER == scd.cus_number && p.isCurrent == true select p;
c = co.First();
//update email and and address
c.EMAIL = Helper.CleanInput("mymail#mm.com");
c.ADDRESS = Helper.CleanInput("123 Sheppard");
//instead of updating current record I'd like to add new record to the table to keep historical changes
db.AddToclient(c);
db.SaveChanges();
//I get error that
//An object with the same key already exists in the ObjectStateManager.
//The existing object is in the Modified state. An object can only be added to
//the ObjectStateManager again if it is in the added state.
Complete error
An object with the same key already exists in the ObjectStateManager. The existing object is in the Modified state. An object can only be added to the ObjectStateManager again if it is in the added state.
remove this code db.AddToclient(c); ,rest all is fine,You are already accessing the object by its reference so no need to add it again.It'll get modified when you call savechanges()
or use cloning if you want to add new object c = co.First().Clone();
It's look like you are adding same row to database and error is coming due to addition of same row again having same primary key which DB will not allow.
Try to add new row and make another table that keeps Historical information of old row and a reference as foreign key. You can add a boolean field that keep information regarding deletion let It is IsDeleted.
Hope It will Help
Thanks
The reason db.AddToclient(c); gives the error is because this object is being tracked by the object context, by possibly being in the database.
The best way to accomplish what you are trying to do is something like the following:
var newClient = new client()
{
EMAIL = Helper.CleanInput("mymail#mm.com"),
ADDRESS = Helper.CleanInput("123 Sheppard"),
};
db.AddToclient(newClient);
db.SaveChanges();
In Entity Framework, all objects retrieved from database by default are tracked by ObjectContext instance. Entity Framework internally maps all objects being tracked by his Key. This pattern is called Identity Map. This means that there will be only one instance of an entity per key. So, you don't need to call Add again, since the entity is already on EF map. You just need call SaveChanges to persist modified entities.
In your case you are:
1 - Creating a new instance of EF ObjectContext;
2 - Retrieving entities in your LINQ query;
3 - Changing values of properties of the retrieved entity;
4 - Adding again to the ObjContext; //error!
5 - Calling SaveChanges()
Step 4 is not necessary because the ObjectContext already knows about the retrieved objects.

General best practice for updating a record and its associated relationships in Linq-to-SQL

I have a very general question about updating a record in Linq-to-SQL. Suppose, in my data model, I have a base record (Table - Person) with an m:m relationship to a set of Categories (Table - Category). Therefore, I have an associative table (PersonCategory) that has foreign keys to both a PersonID and CategoryID.
When I want to update a Person, I may have new PersonCategory records to add and may want to remove other PersonCategory records. What is the best practice for doing such a thing? Would I want to remove all records in Person.RelatedPersonCategories and then add new in? Is LINQ-to-SQL smart enough to negotiate what records in the PersonCategory table are actually being added, edited, or deleted (based on looking at its foreign key potentially)?
Thanks for any help!
As long as there is an active instance of the DataContext class to track changes, LINQ to SQL will happily insert/update/delete rows in an associated table everytime objects in the collection that maps the relationship in the model are modified, and the DataContext.SubmitChanges() method is called.
For example:
using (var db = new DataContext())
{
var person = db.Persons.Where(p => p.Name == "Foo").SingleOrDefault();
if (person != null)
{
// Inserts a new row in the 'PersonCategory' table
// associated to the current 'Person'
// and to the 'Category' with name 'Employee'
person.PersonCategories.Add(new PersonCategory() { CategoryName = "Employee" });
// Updates the 'CategoryName' column in the first row
// of the 'PersonCategory' table associated to the current 'Person'
person.PersonCategories(0).CategoryName = "Consultant";
db.SubmitChanges();
}
}
Things are a little different if you are making changes to the model objects in "disconnected" mode, that is when the DataContext instance that was used to initially create those objects no longer is around.
In this case insert/delete operations on associated tables will work just fine when the object having the modified collection is attached to a new DataContext with the Table(TEntity).Attach method, followed by DataContext.SubmitChanges().
However, modifications on any of the existing objects in the collection will not automatically be applied in the associated table. In order to do that, you must manually call the Table(TEntity).Attach method for each object in the collection.
Here is a quote from the MSDN documentation:
When a new entity is attached,
deferred loaders for any child
collections (for example, EntitySet
collections of entities from
associated tables) are initialized.
When SubmitChanges is called, members
of the child collections are put into
an Unmodified state. To update members
of a child collection, you must
explicitly call Attach and specify
that entity.
Here is a concrete example:
// The 'Person' object has been detached
// from the originating 'DataContext', which is now disposed
person.PersonCategories.Add(new PersonCategory() { CategoryName = "Employee" });
person.PersonCategories(0).CategoryName = "Consultant";
using (var db = new DataContext())
{
// Will detect added and deleted objects
// in the 'PersonCategory' collection
db.Person.Attach(person);
// Required to detect and modifications
// to existing objects in the 'PersonCategory' collection
foreach (var personCategory in person.PersonCategories)
{
db.PersonCategory.Attach(personCategory);
}
db.SubmitChanges();
}
From my experience you don't have to do anything special here. PersonCategory is just an entity, and you add or remove instances from the related table instance on a data context as you would for any other entity, via InsertOnSubmit() and DeleteOnSubmit(). Updates to existing PersonCategory objects are handled by the change tracking system.
You certainly don't need to remove all items first and then add new ones back in.
It gets more complex when you look at the model code - provided you have foreign keys set up correctly in the database, the generated model code should completely handle association management as well.
Eg,
Person will have an EntitySet<PersonCategory>
PersonCategory will have an EntityRef<Person> and EntityRef<Category>
Category will have an EntitySet<PersonCategory>.
Whenever changes are made to these fields, the associated objects are updated as well:
If I change the Person property on a PersonCategory to null, the code will also update the related EntitySet<PersonCategory> accordingly by removing that PersonCategory from the prior person's EntitySet<PersonCategory>
If I add a new PersonCategory to a person's EntitySet<PersonCategory>, the code will automatically set the Person property to the new parent Person as well.
So yes, the basic answer is LINQ to SQL is smart enough to handle this for you - as long as you are generating the model code from your database.

Categories

Resources