EF saving multiple instances of same object - entity-framework

Here's the situation. I create 1 object (a product) and then save it through my db context. I then load that product from the database and put them in another object(download) and save that object. EF then creates another db entry for the original product loaded. So now I have two of the same product in the db. Is this working as intended? I thought EF kept track of objects loaded from the database to prevent stuff like this.
Ok here's some random code with one product if you really want it.
product product1 = new product{blah blah blah};
context.Products.add(product1);
context.savechanges();
var prod1 = context.Products.Where(x => x.Id == 1).FirstOrDefault();
user = new User { new Download {product = (product)prod1}};
context.Users.add(user);
context.save(user);

Here's an example:
var prod = context.Products.SingleOrDefault(p => p.Id == 1);
User user = context.Users.Create();
user.Product = prod;
context.Users.Add(user);
context.SaveChanges();
Or more easily...
User user = context.Users.Create();
user.ProductId = productId;
context.Users.Add(user);
context.SaveChanges();

Related

difference between Attach and Single when retrieving an object to the memory

I know I can use foreign key instead putting the whole object in the memory. Just for the curiosity, I wonder which approach is better: using Attach or Single() in this 1-to-Many relationship scenario? Which one is better in terms of performance?
Using Attach();
Player myPlayer = new Player();
myPlayer.FullName = txt_Name.Text;
Team myTeam = new Team { TeamId = Convert.ToInt32(drp_Teams.SelectedValue) };
db.Teams.Attach(myTeam);
myPlayer.CurrentTeam = myTeam;
db.Players.Add(myPlayer);
db.SaveChanges();
And using Single():
Player myPlayer = new Player();
myPlayer.FullName = txt_Name.Text;
int teamId = Convert.ToInt32(drp_Teams.SelectedValue);
myPlayer.CurrentTeam = db.Teams.Single(t => t.TeamId == teamId);
db.Players.Add(myPlayer);
db.SaveChanges();
Single is always fetching data from database no matter is this data already loaded into context or not. First approach will not query database for the Team entity - thus it's better in your scenario.

Which is the good way to update object in EF6

I have searched and find 2 way to update object in EF
var attachedEntity = _context.EntityClasses.Local.First(t => t.Id == entity.Id);
//We have it in the context, need to update.
if (attachedEntity != null)
{
var attachedEntry = _context.Entry(attachedEntity);
attachedEntry.CurrentValues.SetValues(entity);
}
else
{
////If it's not found locally, we can attach it by setting state to modified.
////This would result in a SQL update statement for all fields
////when SaveChanges is called.
var entry = _context.Entry(entity);
entry.State = EntityState.Modified;
}
_context.SaveChanges();
And other way is seem more easy
var entity = _context.EntityClasses.FirstOrDefault(t => t.Id == entity.Id);
_context.Entry(entity ).EntityState.Modified
_context.SaveChanges();
What is best way to update object?
NOTE: the performence is importance with me
_context.EntityClasses.Local.First(t => t.Id == entity.Id)
=> means that you want to double check the entity on local (the latest loading from DB) and it is not send to DB to find the record so the performance is faster.
_context.EntityClasses.FirstOrDefault(t => t.Id == entity.Id): This command is look up the entity in DB. That means EF creates the query and look up in DB.
The below link is the difference of between Entity.Local.Find & Entity.Find http://msdn.microsoft.com/en-us/data/jj592872.aspx
Hope it helps!

What should be asserted/tested when inserting an entity in the database/repository

This is my integration test code:
// Arrange
var user = new User() { FirstName = "test", UserId = 4, LastName = "test", RegisteredAt = new DateTime(2013, 02, 02) };
var repository = new GenericRepository<User>(_context);
// Act
repository.Add(user);
_context.SaveChanges();
// Assert
Assert.IsNotNull(user.UserId);
I have seen people doing a IsNotNull test with the UserId which makes no sense as the UserId should be never a nullable integer.
What and how would YOU test to make sure the entity you created and added into the database is the same?
Would you do:
var dbUser = _context.Users.First(u => u.FirstName == "test")
and then
Assert.AreEqual(dbUser.FirstName,user.FirstName)
and this for all properties you created?
UPDATE
I have googled a bit more and the people are really doing different and weird things to test wether an entity was inserted into the database:
Assert.That(1, Is.EqualTo(context.Roads.Count()));
Assert.assertNotNull(repo.findUserById(user.getId()));
ICustomer retainedCustomer = repository.
Customers.
Where(q => q.CustomerName == expectedCustomerName).
FirstOrDefault();
Assert.IsNotNull(retainedCustomer);
The first does not even test the inserted entity called road it is checking the count of the road table...
The second and the third assertion seem wrong in my opinion because they use the repository methods with login in it which could fail in a later test to get the inserted customer/user.
What do you think?

How to INSERT only new relation and DELETE a Existing relation - many to many Entity Framework 4.0

I have 3 Tables with many-to-many relationaship
Questions - (QuestionId, Question)
Tags - (TagId, TagName)
QuestionTag - (QuestionId, TagId)
I have a scenario where users ask questions and they can add related tags to it.
Later if they need to add some new tag(which is already in the database) for the existing questing, How to do it?
I need to add only the questionId and TagId into "QuestionTag" table without adding new question or tag as they are already added in the table. How to do it?
I found a similar question at the link Insert/Update Many to Many Entity Framework . How do I do it?
which has the similar scenario where new question is added and tags which are already in the database are mapped.
using (var context = new MyContext())
{
var question= new Question { Question = "I have a question" };
Tag tag1 = context.Tags.FirstOrDefault(s => s.Name == "C#");
Tag tag2 = context.Tags.FirstOrDefault(s => s.Name == ".net");
question.Tags.Add(tag1);
question.Tags.Add(tag2);
context.AddToQuestiones(question);
context.SaveChanges();
}
So to work with my scenario, I modified the above code as
var question= context.Question.FirstOrDefault(q => q.QuestionId == 1);
But I got the following exception.
"The relationship between the two objects cannot be defined because
they are attached to different ObjectContext objects."
Also how delete the questiontag from "QuestionTag" for any question suppose if they are wrongly added with mismatch tag name.
Help me out to resolve this.
Don't add the question to the context (with context.AddToQuestiones(question)), you are only changing a relationship and don't want to create a new entitiy in the database:
using (var context = new MyContext())
{
Question question = context.Question.FirstOrDefault(q => q.QuestionId == 1);
Tag tag1 = context.Tags.FirstOrDefault(s => s.Name == "C#");
Tag tag2 = context.Tags.FirstOrDefault(s => s.Name == ".net");
question.Tags.Add(tag1);
question.Tags.Add(tag2);
context.SaveChanges();
}
If you want to remove a tag load the question including the tags from the database and then remove the tag from the loaded collection:
using (var context = new MyContext())
{
Question question = context.Question.Include("Tags")
.FirstOrDefault(q => q.QuestionId == 1);
// Retrieve the tag from the already loaded collection,
// you don't need to query the DB again for the tag
Tag tagToRemove = question.Tags.FirstOrDefault(s => s.Name == "C#");
if (tagToRemove != null)
question.Tags.Remove(tagToRemove);
context.SaveChanges();
}
Make sure that you use the same context instance for loading the question and the tags. The exception you are having indicates that you are working with multiple different contexts.

.Net Entity Framework SaveChanges is adding without add method

I'm new to the entity framework and I'm really confused about how savechanges works. There's probably a lot of code in my example which could be improved, but here's the problem I'm having.
The user enters a bunch of picks. I make sure the user hasn't already entered those picks.
Then I add the picks to the database.
var db = new myModel()
var predictionArray = ticker.Substring(1).Split(','); // Get rid of the initial comma.
var user = Membership.GetUser();
var userId = Convert.ToInt32(user.ProviderUserKey);
// Get the member with all his predictions for today.
var memberQuery = (from member in db.Members
where member.user_id == userId
select new
{
member,
predictions = from p in member.Predictions
where p.start_date == null
select p
}).First();
// Load all the company ids.
foreach (var prediction in memberQuery.predictions)
{
prediction.CompanyReference.Load();
}
var picks = from prediction in predictionArray
let data = prediction.Split(':')
let companyTicker = data[0]
where !(from i in memberQuery.predictions
select i.Company.ticker).Contains(companyTicker)
select new Prediction
{
Member = memberQuery.member,
Company = db.Companies.Where(c => c.ticker == companyTicker).First(),
is_up = data[1] == "up", // This turns up and down into true and false.
};
// Save the records to the database.
// HERE'S THE PART I DON'T UNDERSTAND.
// This saves the records, even though I don't have db.AddToPredictions(pick)
foreach (var pick in picks)
{
db.SaveChanges();
}
// This does not save records when the db.SaveChanges outside of a loop of picks.
db.SaveChanges();
foreach (var pick in picks)
{
}
// This saves records, but it will insert all the picks exactly once no matter how many picks you have.
//The fact you're skipping a pick makes no difference in what gets inserted.
var counter = 1;
foreach (var pick in picks)
{
if (counter == 2)
{
db.SaveChanges();
}
counter++;
}
I've tested and the SaveChanges doesn't even have to be in the loop.
The below code works, too.
foreach (var pick in picks)
{
break;
}
db.SaveChanges()
There's obviously something going on with the context I don't understand. I'm guessing I've somehow loaded my new picks as pending changes, but even if that's true I don't understand I have to loop over them to save changes.
Can someone explain this to me?
Here's updated working code based on Craig's responses:
1) Remove the Type then loop over the results and populate new objects.
var picks = (from prediction in predictionArray
let data = prediction.Split(':')
let companyTicker = data[0]
where !(from i in memberQuery.predictions
select i.Company.ticker).Contains(companyTicker)
select new //NO TYPE HERE
{
Member = memberQuery.member,
Company = db.Companies.Where(c => c.ticker == companyTicker).First(),
is_up = data[1] == "up", // This turns up and down into true and false.
}).ToList();
foreach (var prediction in picks)
{
if (includePrediction)
{
var p = new Prediction{
Member = prediction.Member,
Company = prediction.Company,
is_up = prediction.is_up
};
db.AddToPredictions(p);
}
}
2) Or if I don't want the predictions to be saved, I can detach the predictions.
foreach (var prediction in picks) {
if (excludePrediction)
{
db.Detach(prediction)
}
}
The reason is here:
select new Prediction
{
Member = memberQuery.member,
These lines will (once the IEnumerable is iterated; LINQ is lazy) :
Instantiate a new Prediction
Associate that Prediction with an existing Member, *which is attached to db.
Associating an instance of an entity with an attached entity automatically adds that entity to the context of the associated, attached entity.
So as soon as you start iterating over predictionArray, the code above executes and you have a new entity in your context.