Linq/Entity Framework syntax for adding a record to a database - linq

I need to add a record to a database using the Entity Framework. Since I'm brand new to using this syntax I am not sure how to properly write the code (Below is my best guess).
First, the agent must have their info inserted into the Agent table. This table produces a self-incrementing primary key known as a SymNumber. I then need to take that SymNumber and use it as a primary key for an insert into the AgentIdentification table.
I have run this code a couple of times, and I do not come up with an error, however since I am using a unit test to test the code I cannot tell for sure if the agent is being added properly. Secondly, I know for a fact that I am not correctly grabbing the SymNumber as generated by the Agent table after the first insert. The SymNumber is an int value in the Linq code set to 0, and this does not change during the AgentIdentification insert.
Any help would be greatly appreciated!
AgentResourcesEntities _db = new AgentResourcesEntities();
try
{
Agent agent = new Agent();
agent.EntityType = "P";
agent.FirstName = agentNewTraining.FirstName;
agent.LastName = agentNewTraining.LastName;
agent.LastChangeOperator = agentNewTraining.Requestor;
agent.LastChangeDate = DateTime.Now;
if (!String.IsNullOrEmpty(agentNewTraining.NameSuffix)) agent.NameSuffix = agentNewTraining.NameSuffix;
_db.Agent.AddObject(agent);
AgentIdentification agentIdentification = new AgentIdentification();
agentIdentification.SymNumber = agent.SymNumber;
agentIdentification.ReferenceType = "S";
agentIdentification.DummyReference = 0;
agentIdentification.LastChangeOperator = agentNewTraining.Requestor;
agentIdentification.LastChangeDate = DateTime.Now;
_db.AgentIdentification.AddObject(agentIdentification);
return true;
}
catch (Exception)
{
return false;
}

First you need to call
_db.SaveChanges();
to get your changed persisted.
But if you want also synchronize (get the new generated value) your agent.SymNumber you will need to call SaveChanges() right after adding it to context.
So the code will be like:
/// ...... ////
_db.Agent.AddObject(agent);
_db.SaveChanges();
AgentIdentification agentIdentification = new AgentIdentification();
agentIdentification.SymNumber = agent.SymNumber; // sym number is now synchronized from DB
///...../////
_db.AgentIdentification.AddObject(agentIdentification);
_db.SaveChanges();
But if SymNumber is foreign key so the AgentIdentification has could have reference to some Agent instance, you can just tie those instances with that reference and would not need to call that additional SaveChanges() in the middle.

Call _db.SaveChanges() after inserting.

Related

MVC - Adding data into linker tables

I have a registration form that allows a school to register. In addition to the obvious login and general details the school can pick from a list of facilities and accreditations that they have.
My data is displayed lovely and binded correctly.
Problem Entering the data into the linker tables does not work it throws an error in both the different ways that I have tried:
Method1:
MembershipUser membershipUser = null;
if (schoolRegisterModel != null)
{
if (null != DB)
{
school SchoolUser = new school();
SchoolUser.username = schoolRegisterModel.UserName;
SchoolUser.email = schoolRegisterModel.Email;
string sPassowrdSalt = Security.Instance().CreateSalt();
SchoolUser.password = Security.Instance().CreatePasswordHash(schoolRegisterModel.Password, sPassowrdSalt);
SchoolUser.password_salt = sPassowrdSalt;
..More data etc..
foreach (var item in schoolRegisterModel.Facilities)
{
if (item.#checked)
{
school_facility sf = new school_facility();
sf.facility_id = item.facility_id;
SchoolUser.school_facility.Add(sf);
}
}
foreach (var item in schoolRegisterModel.Accreditations)
{
if (item.#checked)
{
school_accreditation sa = new school_accreditation();
sa.accreditation_id = item.accreditation_id;
SchoolUser.school_accreditation.Add(sa);
}
}
DB.schools.Add(SchoolUser);
DB.SaveChanges();
Error: {"The INSERT statement conflicted with the FOREIGN KEY constraint \"FK_school_facility_facility\". The conflict occurred in database \"MYDB\", table \"dbo.facility\", column 'facility_id'.\r\nThe statement has been terminated."}
Also - Do I need to manually retrieve the soon to be school ID that will be generated based on this insert. This method avoids entering data directly into the linker tables using only the primary table (school).
Method2:
Same code again apart from trying to update the primary tables (school) accreditation and facilities collection directly, I manually update the linker tables seperately using the latest primary key generated by the previous query, code for this is as follows:
MembershipUser membershipUser = null;
if (schoolRegisterModel != null)
{
if (null != DB)
{
school SchoolUser = new school();
SchoolUser.username = schoolRegisterModel.UserName;
SchoolUser.email = schoolRegisterModel.Email;
string sPassowrdSalt = Security.Instance().CreateSalt();
SchoolUser.password = Security.Instance().CreatePasswordHash(schoolRegisterModel.Password, sPassowrdSalt);
SchoolUser.password_salt = sPassowrdSalt;
..More data etc..
// Linker data for facilities and accreditations.
// Facilities
foreach (var item in schoolRegisterModel.Facilities)
{
if (item.#checked)
{
school_facility sf = new school_facility();
sf.facility_id = item.facility_id;
sf.school_id = SchoolUser.school_id;
DB.school_facility.Add(sf);
}
}
// Accreditations
foreach (var item in schoolRegisterModel.Accreditations)
{
if (item.#checked)
{
school_accreditation sa = new school_accreditation();
sa.accreditation_id = item.accreditation_id;
sa.school_id = SchoolUser.school_id;
DB.school_accreditation.Add(sa);
}
}
m_DB.SaveChanges();
Error: {"The INSERT statement conflicted with the FOREIGN KEY constraint \"FK_school_facility_facility\". The conflict occurred in database \"MYDB\", table \"dbo.facility\", column 'facility_id'.\r\nThe statement has been terminated."}
If you guys have any idea where I am going wrong then please do let me know. There seem to be examples of updating linker table date (which I will need at some point anyway) but can't find an example of my problem...
Thanks in advance.
Looks like I have found the answer:
MVC: The INSERT statement conflicted with the FOREIGN KEY constraint
My data being pulled through was basically not containing the correct foreign key value (0 - which didn't exist) and quite rightly my DB was throwing the error. Sorry for wasting time to whoever read and thanks for your time. I hope this can help somebody else.
Joe

Entity Framework Optimistic Concurrency Exception not occuring

We have an ASP.Net MVC application that uses EF4 as its data access layer and we're seeing unexpected behaviour with regards to OptimisitcConcurrencyExceptions not being thrown when we think they should be.
We have simplified the problem down to the following code...
using System.Linq;
using Project.Model;
namespace OptimisticConcurrency
{
class Program
{
static void Main()
{
Contact firstContact = null;
using (var firstEntities = new ProjectEntities())
{
firstContact = (from c in firstEntities.Contacts
where c.LastName == "smith" select c).Single();
}
using (var secondEntities = new ProjectEntities())
{
var secondContact = (from c in secondEntities.Contacts
where c.LastName == "smith" select c).Single();
secondContact.Title = "a";
secondEntities.SaveChanges();
}
firstContact.Title = "b";
using (var thirdEntities = new ProjectEntities())
{
var thirdContact = (from c in thirdEntities.Contacts
where c.LastName == "smith" select c).Single();
thirdContact.Title = firstContact.Title;
//EXPLICITLY SET VERSION HERE
thirdContact.Version = firstContact.Version;
thirdEntities.SaveChanges();
}
}
}
}
This is a rather simple version of what happens in our MVC app, but the same problem occurs.
When we call SaveChanges on the thirdEntities, I expect the exception and nothing is being thrown.
Much more interestingly, when we attach the SQL Profiler, we see that the Version is being used in the where clause but it is thirdEntities Version value (the current one in the DB) being used, not the firstEntities values DESPITE it being explicitly set immediately before SaveChanges is called. SaveChanges is resetting the Version to be the retrieved value not the set value.
In the EDMX, the Version is set to have a StoreGeneratedPattern is set to Computed.
Anyone have any idea what is going on here?
This is a problem. Once the column is set to Computed you can't set its value in the application (you can but the value is not used).
Edit:
If you load entity from database it is by default tracked with the context. The context stores its original values. Original values are for example used for snapshot change tracking but they are also used as the only valid source of Computed properties. If you set Computed property in your entity the value is not used and original value is used insted. The workaround is to modify original value (before you modify anything else):
using (var context = new TestEntities())
{
var entityToUpdate = context.MyEntities.Single(e => e.Id == someId);
entityToUpdate.Timestamp = entity.Timestamp;
ObjectStateEntry entry = context.ObjectStateManager.GetObjectStateEntry(entityToUpdate);
entry.ApplyOriginalValues(entityToUpdate);
// set modified properties
context.SaveChanges();
}
Edit 2:
Btw. once you have both actually loaded timestamp and previously retrieved timestamp you can simply compare them in your application instead of doing it in the database.

ef4 poco,how get id after insert?

I am inserting a document and i want references id of document to a part of this
document...but the code is autoincrement, and i am using poco. how i can get
back the code of insert file?
ArquivoDTO file = new ArquivoDTO();
file.NomeArquivo = fileName;
file.TipoArquivo = fileType;
file.TamanhoArquivo = fileSize;
var context = new PROGISContext();
ArquivoRepository arquivoRepository = new ArquivoRepository(context);
arquivoRepository.IncluirArquivo(file); //insert file
ParteArquivoDTO part = new ParteArquivoDTO(); //create a part
part.CodArquivo = file.CodArquivo; // here id of inserted file
Something like this
[Key, DatabaseGenerated( DatabaseGeneratedOption.Identity )]
public Guid Identifier { get; protected set; }
However you won't get the I'd untill you call SaveChanges()
It's kind of hard to say what's the problem with this code sample alone, but are you calling SubmitChanges() on your DataContext in arquivoRepository.IncluirArquivo(file)?
If you are, and the CodArquivo property of your ArquivoDTO class it correctly configured to be an auto increment ID, then the property should get updated automatically after SubmitChanges().

Auditing in Entity Framework

After going through Entity Framework I have a couple of questions on implementing auditing in Entity Framework.
I want to store each column values that is created or updated to a different audit table.
Right now I am calling SaveChanges(false) to save the records in the DB(still the changes in context is not reset). Then get the added | modified records and loop through the GetObjectStateEntries. But don't know how to get the values of the columns where their values are filled by stored proc. ie, createdate, modifieddate etc.
Below is the sample code I am working on it.
// Get the changed entires( ie, records)
IEnumerable<ObjectStateEntry> changes = context.ObjectStateManager.GetObjectStateEntries(EntityState.Modified);
// Iterate each ObjectStateEntry( for each record in the update/modified collection)
foreach (ObjectStateEntry entry in changes)
{
// Iterate the columns in each record and get thier old and new value respectively
foreach (var columnName in entry.GetModifiedProperties())
{
string oldValue = entry.OriginalValues[columnName].ToString();
string newValue = entry.CurrentValues[columnName].ToString();
// Do Some Auditing by sending entityname, columnname, oldvalue, newvalue
}
}
changes = context.ObjectStateManager.GetObjectStateEntries(EntityState.Added);
foreach (ObjectStateEntry entry in changes)
{
if (entry.IsRelationship) continue;
var columnNames = (from p in entry.EntitySet.ElementType.Members
select p.Name).ToList();
foreach (var columnName in columnNames)
{
string newValue = entry.CurrentValues[columnName].ToString();
// Do Some Auditing by sending entityname, columnname, value
}
}
Here you have two basic options:
Do it at the database level
Do it in the c# code
Doing it at the data base level, means using triggers. In that case there is no difference if you are using enterprise library or another data access technology.
To do it in the C# code you would add a log table to your datamodel, and write the changes to the log table. When you do a save changes both the changes to the data and the information which you wrote to the log table would be saved.
Are you inserting the new record using a stored proc? If not (i.e. you are newing up an object, setting values, inserting on submit and then saving changes the new object id will be automatically loaded into the id property of the object you created. If you are using a stored proc to do the insert then you need to return the ##IDENTITY from the proc as a return value.
EX:
StoreDateContext db = new StoreDataContext(connString);
Product p = new Product();
p.Name = "Hello Kitty Back Scratcher";
p.CategoryId = 5;
db.Products.Add(p);
try
{
db.SaveChanges();
//p.Id is now set
return p.Id;
}
finally
{
db.Dispose;
}

LINQ Submit Changes not submitting changes

I'm using LINQ to SQL and C#. I have two LINQ classes: User and Network.
User has UserID (primary key) and NetworkID
Network has NetworkID (primary key) and an AdminID (a UserID)
The following code works fine:
user.Network.AdminID = 0;
db.SubmitChanges();
However, if I access the AdminID before making the change, the change never happens to the DB. So the following doesn't work:
if(user.Network.AdminID == user.UserID)
{
user.Network.AdminID = 0;
db.SubmitChanges();
}
It is making it into the if statement and calling submit changes. For some reason, the changes to AdminID never make it to the DB. No error thrown, the change just never 'takes'.
Any idea what could be causing this?
Thanks.
I just ran a quick test and it works fine for me.
I hate to ask this, but are you sure the if statement ever returns true? It could be you're just not hitting the code which changes the value.
Other than that we might need more info. What are the properties of that member? Have you traced into the set statement to ensure the value is getting set before calling SubmitChanges? Does the Linq entity have the new value after SubmitChanges? Or do both the database AND the Linq entity fail to take the new value?
In short, that code should work... so something else somewhere is probably wrong.
Here's the original post.
Here's a setter generated by the LinqToSql designer.
Code Snippet
{
Contact previousValue = this._Contact.Entity;
if (((previousValue != value)
|| (this._Contact.HasLoadedOrAssignedValue == false)))
{
this.SendPropertyChanging();
if ((previousValue != null))
{
this._Contact.Entity = null;
previousValue.ContactEvents.Remove(this);
}
this._Contact.Entity = value;
if ((value != null))
{
value.ContactEvents.Add(this);
this._ContactID = value.ID;
}
else
{
this._ContactID = default(int);
}
this.SendPropertyChanged("Contact");
}
}
This line sets the child's property to the parent.
this._Contact.Entity = value;
This line adds the child to the parent's collection
value.ContactEvents.Add(this);
The setter for the ID does not have this second line.
So, with the autogenerated entities...
This code produces an unexpected behavior:
myContactEvent.ContactID = myContact.ID;
This code is good:
myContactEvent.Contact = myContact;
This code is also good:
myContact.ContactEvents.Add(myContactEvent);
I had this issue. The reason was one dumb line of code:
DBDataContext db { get { return new DBDataContext(); } }
obviously it should be:
DBDataContext db = new DBDataContext();

Resources