i know how to do updates, inserts and deletes with the entityframework but in this case i don't know what to do.
In this case i have 3 tables: the table A the table B and the table AB which has 2 columns, one is the foreing key of the table A and one is the foreing key of the table B.
The entity framework shows only the tables A and B so how i can update only the content of the table AB?
I've tried to use the references in entity A and entity B but it gives me an exception saying that the entityset AB doesn't have the insert function and the delete function.
You try to make a
Public Virtual List<int> Ids
in your "A" and "B" Class to recover all the associations
For an insert, you would create a record for Table A, then add the Table B records to the item created that inserts into A. EF will handle the rest.
var tableA = new TableAtype { Description = "blah", etc.};
tableA.TableBtype.Add(new TableBtype { Property1 = "foo", Property2 = "bar"};
yourContext.AddToTableAtype(tableA);
yourContext.SaveChanges();
i'll be more specific using the code of my project as asked by TheGeekYouNeed
public void ModificaAbilitazioni(int IdGruppoAnagrafica, List<DefAbilitazioni> AbilitazioniList)
{
GruppiAnag gruppo = (from g in entities.GruppiAnags
where g.IdGruppoAnag == IdGruppoAnagrafica
select g).First();
List<DefAbilitazioni> tutteAbilitazioni = GetTutteAbilitazioni();
for (int i = 0; i < AbilitazioniList.Count; i++)
{
if (tutteAbilitazioni[i].GruppiAnags.Contains(gruppo))
{
tutteAbilitazioni[i].GruppiAnags.Remove(gruppo);
}
}
foreach (DefAbilitazioni abilitazione in AbilitazioniList)
{
for (int i = 0; i < tutteAbilitazioni.Count; i++)
{
if (tutteAbilitazioni[i].IdAbilitazione == abilitazione.IdAbilitazione)
{
tutteAbilitazioni[i].GruppiAnags.Add(gruppo);
}
}
}
entities.SaveChanges();
}
ok...here it is
this method should change the privilegies accounts.
First i recover the account using his id, than i recover all the privilegies and if in their reference they have the account recovered, then i remove it from the reference.
This way the account doesn't have any privilegies. Now in the privilegies that i've passed calling the method and in theri reference i put the account. (just a wipe and refill i'm just trying for now...)
i've also di the opposite, wiping the privilegies references in the account and refill them, but in both way won't work, in the first case it says that the third entity (AB) doesn't have the insert function
i've resolved the thing, the problem was that i was working with objects not attached to the db, i've tried with the attach like this
foreach (DefAbilitazioni abilitazione in abilitazioni)
{
entities.Attach(abilitazione);
gruppo.DefAbilitazionis.Add(abilitazione);
}
but it doesn't work it says that the entitykey is null, maybe if somebody gives me an example of using the attach i'll try to change my code that now is like this
public void ModificaAbilitazioni(int IdGruppoAnagrafica, List<DefAbilitazioni> AbilitazioniList)
{
GruppiAnag gruppo = (from g in entities.GruppiAnags
where g.IdGruppoAnag == IdGruppoAnagrafica
select g).First();
IEnumerable<int> idAbilitazioni = from id in AbilitazioniList
select id.IdAbilitazione;
List<DefAbilitazioni> abilitazioni = (from abilitazione in entities.DefAbilitazionis
where idAbilitazioni.Contains(abilitazione.IdAbilitazione)
select abilitazione).ToList();
gruppo.DefAbilitazionis.Clear();
foreach (DefAbilitazioni abilitazione in abilitazioni)
{
gruppo.DefAbilitazionis.Add(abilitazione);
}
entities.SaveChanges();
}
Related
I am having trouble with en EF method returning duplicate rows of data. When I am running this, in my example, it returns four rows from a database view. The fourth row includes details from the third row.
The same query in SSMS returns four individual rows with the correct details. I have read somewhere about EK and problems with optimization when there are no identity column. But - is there anyway to alter the below code to force EK to read all records with all details?
public List<vs_transactions> GetTransactionList(int cID)
{
using (StagingDataEntities db = new StagingDataEntities())
{
var res = from trans in db.vs_transactions
where trans.CreditID == cID
orderby trans.ActionDate descending
select trans;
return res.ToList();
}
}
Found the solution :) MergeOption.NoTracking
public List<vs_transactions> GetTransactionList(int cID)
{
db.vs_transactions.MergeOption = MergeOption.NoTracking;
using (StagingDataEntities db = new StagingDataEntities())
{
var res = from trans in db.vs_transactions
where trans.CreditID == cID
orderby trans.ActionDate descending
select trans;
return res.ToList();
}
}
I have two tables Employee (n) and Store (1), which have n:1 relationship.
Employee has foreign key idStore which is primary key from Store.
Here is how I try to delete a row from Employee:
public void deleteEmployee(int idEmployee)
{
MyEntities pe = new MyEntities();
try
{
var firstQuery = from e in pe.Employees
where e.idEmployee == idEmployee
select e;
string findIdStore = firstQuery.First().StoreReference.EntityKey.EntityKeyValues[0].Value.ToString();
int idStore = Int32.Parse(findIdStore);
Store r = pe.Stores.First(c => c.idStore == idStore);
r.Employees.Remove(firstQuery.First());
pe.DeleteObject(firstQuery.First());
pe.SaveChanges();
}
catch (Exception ex)
{
return;
}
}
And still, I get error that the delete statement conflicted with the reference constraint.
The complete error is here:
The DELETE statement conflicted with the REFERENCE constraint
"FK_Bill_Employee". The conflict occurred in database
"myDatabase", table "dbo.Bill", column 'idEmployeeMember'.
The statement has been terminated.
Can't you just find and delete the employee??
public void deleteEmployee(int idEmployee)
{
using(MyEntities pe = new MyEntities())
{
var emmployeeToDelete = pe.Employees.FirstOrDefault(e => e.idEmployee == idEmployee);
if(employeeToDelete != null)
{
pe.DeleteObject(employeeToDelete);
pe.SaveChanges();
}
}
}
I don't think you need to do anything more than this, really.....
Next time when you load this particular store the employee belonged to, that employee will no longer be in the store's collection of employees - without doing any messy manual deletes or anything....
could you help with this? I bet this isn't any tough one..but am new to EF and facing a weekend deadline. I want to update a table with values.. but the primary key is identity column. So my task is like this.. if it exists, update.. if it doesn't add to the
table.. this is my code..and am stuck in this else part..!
Table structure is like this
Primary Key table - System: SystemId, SystemName
Foreign Key table - SystemConfiguration: SystemConfigurationId, SystemId, SystemRAM, SystemHard-Disk
public void SaveSystemConfigurations(SystemConfiguration systemConfig)
{
var config = (from s in Context.SystemConfiguration
where s.SystemId == systemConfig.SystemId
select s).FirstOrDefault();
if (config == null)
{
Context.SystemConfigurations.AddObject(systemConfig);
Context.SaveChanges();
}
else
{
// EntityKey systemConfigKey= new EntityKey("systemConfig", "systemConfigId", config.SystemConfigurationId);
Context.SystemConfigurations.Attach(systemConfig);
Context.SaveChanges();
}
}
Try this:
public void SaveSystemConfigurations(SystemConfiguration systemConfig)
{
var config = (from s in Context.SystemConfiguration
where s.SystemId == systemConfig.SystemId
select s).FirstOrDefault();
if (config == null)
{
Context.SystemConfigurations.AddObject(systemConfig);
}
else
{
config.Attribute = value; // Do your update here
}
Context.SaveChanges();
}
Edit. It should be config not systemConfig.
The ApplyCurrentValues method will apply scalar attributes to an entity that matches the same key. My assumption is that you are modifying a real entity (an object that has a valid entity key).
This would work:
var eSet = config.EntityKey.EntitySetName;
Context.ApplyCurrentValues(eSet, systemConfig);
Context.SaveChanges();
public void SaveSystemConfigurations(SystemConfiguration systemConfig)
{
var context = new EntitiesModel();
//here is the name of the partial class created on the Context area of the edmx designer.cs
var config = (from s in context.SystemConfiguration
where s.SystemId == systemConfig.SystemId
select s).FirstOrDefault();
context.ApplyCurrentValues(config.EntityKey.EntitySetName, systemConfig);
// systemConfig comes from the view with values set by the user
// you dont have to manually need to map one value at the time
context.SaveChanges();
}
Ok, I must be working too hard because I can't get my head around what it takes to use the Entity Framework correctly.
Here is what I am trying to do:
I have two tables: HeaderTable and DetailTable. The DetailTable will have 1 to Many records for each row in HeaderTable. In my EDM I set up a Relationship between these two tables to reflect this.
Since there is now a relationship setup between these tables, I thought that by quering all the records in HeaderTable, I would be able to access the DetailTable collection created by the EDM (I can see the property when quering, but it's null).
Here is my query (this is a Silverlight app, so I am using the DomainContext on the client):
// myContext is instatiated with class scope
EntityQuery<Project> query = _myContext.GetHeadersQuery();
_myContext.Load<Project>(query);
Since these calls are asynchronous, I check the values after the callback has completed. When checking the value of _myContext.HeaderTable I have all the rows expected. However, the DetailsTable property within _myContext.HeaderTable is empty.
foreach (var h in _myContext.HeaderTable) // Has records
{
foreach (var d in h.DetailTable) // No records
{
string test = d.Description;
}
I'm assuming my query to return all HeaderTable objects needs to be modified to somehow return all the HeaderDetail collectoins for each HeaderTable row. I just don't understand how this non-logical modeling stuff works yet.
What am I doing wrong? Any help is greatly appriciated. If you need more information, just let me know. I will be happy to provide anything you need.
Thanks,
-Scott
What you're probably missing is the Include(), which I think is out of scope of the code you provided.
Check out this cool video; it explained everything about EDM and Linq-to-Entities to me:
http://msdn.microsoft.com/en-us/data/ff628210.aspx
In case you can't view video now, check out this piece of code I have based on those videos (sorry it's not in Silverlight, but it's the same basic idea, I hope).
The retrieval:
public List<Story> GetAllStories()
{
return context.Stories.Include("User").Include("StoryComments").Where(s => s.HostID == CurrentHost.ID).ToList();
}
Loading the the data:
private void LoadAllStories()
{
lvwStories.DataSource = TEContext.GetAllStories();
lvwStories.DataBind();
}
Using the data:
protected void lvwStories_ItemDataBound(object sender, ListViewItemEventArgs e)
{
if (e.Item.ItemType == ListViewItemType.DataItem)
{
Story story = e.Item.DataItem as Story;
// blah blah blah....
hlStory.Text = story.Title;
hlStory.NavigateUrl = "StoryView.aspx?id=" + story.ID;
lblStoryCommentCount.Text = "(" + story.StoryComments.Count.ToString() + " comment" + (story.StoryComments.Count > 1 ? "s" : "") + ")";
lblStoryBody.Text = story.Body;
lblStoryUser.Text = story.User.Username;
lblStoryDTS.Text = story.AddedDTS.ToShortTimeString();
}
}
I'm currently inserting/updating fields like this (if there's a better way, please say so - we're always learning)
public void UpdateChallengeAnswers(List<ChallengeAnswerInfo> model, Decimal field_id, Decimal loggedUserId)
{
JK_ChallengeAnswers o;
foreach (ChallengeAnswerInfo a in model)
{
o = this.FindChallengeAnswerById(a.ChallengeAnswerId);
if (o == null) o = new JK_ChallengeAnswers();
o.answer = FilterString(a.Answer);
o.correct = a.Correct;
o.link_text = "";
o.link_url = "";
o.position = FilterInt(a.Position);
o.updated_user = loggedUserId;
o.updated_date = DateTime.UtcNow;
if (o.challenge_id == 0)
{
// New record
o.challenge_id = field_id; // FK
o.created_user = loggedUserId;
o.created_date = DateTime.UtcNow;
db.JK_ChallengeAnswers.AddObject(o);
}
else
{
// Update record
this.Save();
}
}
this.Save(); // Commit changes
}
As you can see there is 2 times this.Save() (witch invokes db.SaveChanges();)
when Adding we place the new object into a Place Holder with the AddObject method, in other words, the new object is not committed right away and we can place as many objects we want.
But when it's an update, I need to Save first before moving on to the next object, is there a method that I can use in order to, let's say:
if (o.challenge_id == 0)
{
// New record
o.challenge_id = field_id;
o.created_user = loggedUserId;
o.created_date = DateTime.UtcNow;
db.JK_ChallengeAnswers.AddObject(o);
}
else
{
// Update record
db.JK_ChallengeAnswers.RetainObject(o);
}
}
this.Save(); // Only save once when all objects are ready to commit
}
So if there are 5 updates, I don't need to save into the database 5 times, but only once at the end.
Thank you.
Well if you have an object which is attached to the graph, if you modify values of this object, then the entity is marked as Modified.
If you simply do .AddObject, then the entity is marked as Added.
Nothing has happened yet - only staging of the graph.
Then, when you execute SaveChanges(), EF will translate the entries in the OSM to relevant store queries.
Your code looks a bit strange. Have you debugged through (and ran a SQL trace) to see what is actually getting executed? Because i can't see why you need that first .Save, because inline with my above points, since your modifying the entities in the first few lines of the method, an UPDATE statement will most likely always get executed, regardless of the ID.
I suggest you refactor your code to handle new/modified in seperate method. (ideally via a Repository)
Taken from Employee Info Starter Kit, you can consider the code snippet as below:
public void UpdateEmployee(Employee updatedEmployee)
{
//attaching and making ready for parsistance
if (updatedEmployee.EntityState == EntityState.Detached)
_DatabaseContext.Employees.Attach(updatedEmployee);
_DatabaseContext.ObjectStateManager.ChangeObjectState(updatedEmployee, System.Data.EntityState.Modified);
_DatabaseContext.SaveChanges();
}