Committing new data to database via EF, Errors ensue with Attaching/Adding - asp.net

So I'm starting out with EF on my website (C#) and Ive run into a bit of a snag. A user can either create or modify data and they will do that with the selection screen (page 1). If a user selects to create new data, I will perform the following code:
Program newProg = new Program();
using (DatabaseEntities context = new DatabaseEntities())
{
Guid id = new Guid(list.SelectedValue);
var itemString = from item in context.Set where item.Id == id select item;
Item selectedItem = itemString.ToList()[0];
newProg.Items.Add(selectedItem);
context.AddToProgramSet(newProg);
context.Detach(newProg);
}
Pretty much creating a new instance of the 'Program' which will be passed along each user control until the user is ready to submit to the database. At that point the following code will be executed:
using (DatabaseEntities context = new DatabaseEntities())
{
context.AddToProgramSet(this.SummaryControl.SelectedProgram);
context.SaveChanges();
}
Unfortunately when I get there, I receive the following message:
The object cannot be added to the ObjectStateManager because it already has an EntityKey. Use ObjectContext.Attach to attach an object that has an existing key.
at this line:
context.AddToProgramSet(this.SummaryControl.SelectedProgram);
Also, when I add the following line prior to the previous:
context.Attach(this.SummaryControl.SelectedProgram);
I get this error:
An object with a null EntityKey value cannot be attached to an object context.
Any help would be greatly appreciated. Thanks.

The root cause of this error is that you are attempting to add an Entity as a new Entity that already has its primary key set.
At what point do you add the Entities to your SummaryControl? Your first code snippet shows you adding the Entity:
...
newProg.Items.Add(selectedItem);
context.AddToProgramSet(newProg);
context.Detach(newProg);
...
Then you appear to add it again:
using (DatabaseEntities context = new DatabaseEntities())
{
context.AddToProgramSet(this.SummaryControl.SelectedProgram);
context.SaveChanges();
}
If newProg and this.SummaryControl.SelectedProgram are the same Entity, you've attempted to add it twice. Remove the context.AddToProgramSet(newProg); from the first snippet, do you work on the Entity, then add it to the ProgramSet.

Dave is right that the root cause is that the entity already has a primary key.
One thing that you do not show in your code is how:
Program newProg = new Program();
Becomes:
this.SummaryControl.SelectedProgram
One way that you could fix it is by saving newProg to the database before you start adding Items to it.

Related

Cannot implicitly convert type 'string' to 'System.Collections.Generic.ICollection<WebApplication2.Entry>'

I used ado.net entity framework to connect database and have an .edmx file in project.. When I tried to reach objects in code side with object initializer I can see the object names but when I tried to enter a value into textarea in throws this error.Title is a table in database and entries is another tables data but because of both tables has relationship I can see Entries down of Title. What do I have to do? I do not understand anything.. thanks for helps here is the situation
Title a = new Title
{
Entries=textarea.InnerText,
};
Try below, you need to inititialize entry collection with your item by giving correct property value
Title a = new Title
{
Entries= new List<Entry>()
{
new Entry() {PropertyName =textarea.InnerText}
};
};
It's because your Entrires are of type ICollection<Entry> and you trying to store there string variable.

How to use SQL Server 2008 stored procedure in asp.net mvc

I have created a simple stored procedure in SQL Server 2008 as:
CREATE PROCEDURE viewPosts
AS
SELECT * FROM dbo.Post
Now, I have no idea how to use it in controller's action, I have a database object which is:
entities db = new entities();
Kindly tell me how to use stored procedure with this database object in Entity Framework.
For Details check this link:
http://www.entityframeworktutorial.net/data-read-using-stored-procedure.aspx
Hope this will help you.
See article about 30% in:
In the designer, right click on the entity and select Stored Procedure mapping.
Click and then click the drop down arrow that appears. This exposes the list of all Functions found in the DB metadata.
Select Procedure from the list. The designer will do its best job of matching the stored procedure’s parameters with the entity properties using the names. In this case, since all of the property names match the parameter names, it maps every one correctly so you don’t need to make any changes. Note: The designer is not able to automatically detect the name of the field being returned.
Under the Result Column Bindings section, click and enter variable name. The designer should automatically select the entity key property for this final mapping.
The following code is what I use to initialize the stored procedure, then obtain the result into variable returnedResult, which in this case is the record id of a newly created record.
SqlParameter paramResult = new SqlParameter("#Result", -1);
paramResult.Direction = System.Data.ParameterDirection.Output;
var addParameters = new List<SqlParameter>
{
new SqlParameter("#JobID", EvalModel.JobID),
new SqlParameter("#SafetyEvaluator", EvalModel.SafetyEvaluator),
new SqlParameter("#EvaluationGuid", EvalModel.EvaluationGuid),
new SqlParameter("#EvalType", EvalModel.EvalType),
new SqlParameter("#Completion", EvalModel.Completion),
new SqlParameter("#ManPower", EvalModel.ManPower),
new SqlParameter("#EDate", EvalModel.EDate),
new SqlParameter("#CreateDate", EvalModel.CreateDate),
new SqlParameter("#Deficiency", EvalModel.Deficiency.HasValue ? EvalModel.Deficiency.Value : 0),
new SqlParameter("#DeficiencyComment", EvalModel.DeficiencyComment != null ? EvalModel.DeficiencyComment : ""),
new SqlParameter("#Traffic", EvalModel.Traffic.HasValue ? EvalModel.Traffic.Value : 0),
paramResult
};
// Stored procedure name is AddEval
context.Database.ExecuteSqlCommand("AddEval #JobID, #SafetyEvaluator, #EvaluationGuid, #EvalType, #Completion, #ManPower, #EDate, #CreateDate, #Deficiency, #DeficiencyComment, #Traffic, #Result OUTPUT", addParameters.ToArray());
var returnedResult = paramResult.Value;
NewEvaluationID = Convert.ToInt32(returnedResult);

How does Entity Framework decide whether to reference an existing object or create a new one?

Just for my curiosity (and future knowledge), how does Entity Framework 5 decide when to create a new object vs. referencing an existing one? I might have just been doing something wrong, but it seems that every now and then if I do something along the lines of:
using (TestDB db = new TestDB())
{
var currParent = db.Parents.Where(p => p.Prop == passedProp).FirstOrDefault();
if(currParent == null) {
Parent newParent = new Parent();
newParent.Prop = passedProp;
currParent = newParent;
}
//maybe do something to currParent here
var currThing = db.Things.Where(t => t.Prop == passedPropTwo).FirstOrDefault();
currThing.Parent = currParent;
db.SaveChanges();
}
EF will create a new Parent in the database, basically a copy of the currParent, and then set the Parent_ID value of currThing to that copy. Then, if I do it again (as in, if there's already two of those parents), it won't make a new Parent and instead link to the first one. I don't really understand this behavior, but after playing around with it for a while something like:
using (TestDB db = new TestDB())
{
var currParent = db.Parents.Where(p => p.Prop == passedProp).FirstOrDefault();
if(currParent == null) {
Parent newParent = new Parent();
newParent.Prop = passedProp;
currParent = newParent;
}
//maybe do something to currParent here
var currThing = db.Things.Where(t => t.Prop == passedPropTwo).FirstOrDefault();
currThing.Parent = db.Parents.Where(p => p.ID == currParent.ID).First();
db.SaveChanges();
}
seemed to fix the problem. Is there any reason this might happen that I should be aware of, or was there just something weird about the way I was doing it at the time? Sorry I can't be more specific about what the exact code was, I encountered this a while ago and fixed it with the above code so I didn't see any reason to ask about it. More generally, how does EF decide whether to reference an existing item instead of creating a new one? Just based on whether the ID is set or not? Thanks!
If your specific instance of your DBContext provided that specific instance of that entity to you, then it will know what record(s) in the database it represents and any changes you make to it will be proper to that(those) record(s) in the database. If you instantiate a new entity yourself, then you need to tell the DBContext what exactly that record is if it's anything but a new record that should be inserted into your database.
In the special scenario where you have multiple DBContext instances and one instance provides you this entity but you want to use another instance to work with and save the entity, then you have to use ((IObjectContextAdapter)firstDbContext).ObjectContext.Detach() to orphan this entity and then use ((IObjectContextAdapter)secondDbContext).ObjectContext.Parents.Attach() to attach it (or ApplyChanges() if you're also editing it - this will call Attach for you).
In some other special scenarios (your object has been serialized and/or you have self-tracking entities), some additional steps may be required, depending on what exactly you are trying to do.
To summarize, if your specific instance of your DBContext is "aware" of your specific instance of an entity, then it will work with it as if it is directly tied to that specific row in the database.

Entity insert appears to succeed, but doesn't show up in queries

I have a very simple row that I'm inserting using Entity, which I do like so:
var context = GetEntityContext();
SOMEPOCO newobj = new SOMEPOCO
{
Data = data
};
context.SOMEOBJECTS.Add(newobj);
context.SaveChanges();
return newobj.ID;
And newobj.ID (the auto-incremented primary key) is indeed populated. No errors are raised or exceptions thrown. But when I go to SQL Management Studio and query for items or look it up in code, it doesn't show up. But if I manually make an entry in the DB, it increments the primary key as though the previous failed entry were there.
What could be causing this?
Thanks.

How to update an entity without a round-trip? (EF 4)

I tried the following:
public void UpdatePlayer(int id)
{
Player player = new Player() {ID = id};
player.Password = "12";
Entities.Players.Attach(player);
Entities.SaveChanges();
}
No change at the db.
What am I missing?
I think it might be because you're setting the values before you attach the object - the data context will not know what fields have changed. Try:
public void UpdatePlayer(int id)
{
Player player = new Player() {ID = id};
Entities.Players.Attach(player);
player.Password = "12";
Entities.SaveChanges();
}
attach is used for entities that already exist in the database, but you have to attach first, and then edit it, as another poster pointed out.
you should use .Add instead of .Attach if you are creating new items.
FYI Entity Framework 4 - AddObject vs Attach
As already mentioned when you attach entity it is set to Unchanged state so you have to manually set the state to Modified. But be aware that setting the state for whole entity can cause update of all fields. So if your Player entity has more than Id and Password fields all other fields will probably be set to default values. For such case try to use:
Entities.Players.Attach(player);
var objectState = Entities.ObjectStateManager.GetObjectStateEntry(player);
objectState.SetModifiedProperty("Password");
Entities.SaveChanges();
You can also try setting password after attaching the entity:
Entities.Players.Attach(player);
player.Password = "12";
Entities.SaveChanges();
When you attach an entity using Attach method, the entity will go into Unchanged EntityState, that is, it has not changed since it was attached to the context. Therefore, EF will not generate necessary update statement to update the database.
All you need to do is to give a hint to EF by changing the EntityState to Modified:
Entities.Players.Attach(player);
Entities.ObjectStateManager.ChangeObjectState(player, EntityState.Modified)
Entities.SaveChanges();

Resources