How to use EF core owned entites - entity-framework

I am using a SQLite database EFCore 2.0 preview in UWP Project.
The address table is split into to different entities
Delivery address,
Invoice Address
using
modelBuilder.Entity<Project>().OwnsOne(p => p.DeliveryAddress);
which works great for setting up the database, with migrations, creates the different table in the database. With test data that I have put in manually works great at reading data from these tables. But how do I save changes to the DeliveryAddress table. Nothing is getting persisted to the database, when I save the using:
public void UpdateDeliveryAddress(Project modifiedProject)
{
using (var db = new SteelFrameCalculatorDataContext())
{
db.Entry(modifiedProject).State = EntityState.Modified;
db.SaveChanges();
}
}
Project being the parent entity
2017-06-11T23:21:10.9242463+01:00 Warning 8 Microsoft.EntityFrameworkCore.Model.Validation
The key {'ProjectId'} on entity type 'Project.DeliveryAddress->Address' contains properties in shadow state - {'ProjectId'}. To configure this warning use the DbContextOptionsBuilder.ConfigureWarnings API (event id 'CoreEventId.ModelValidationShadowKeyWarning'). ConfigureWarnings can be used when overriding the DbContext.OnConfiguring method or using AddDbContext on the application service provider.
Using the following allowed in to save updates to the database. Assume the UpdateRange(entity) sets all to modified. Not sure if this is the correct way, but it works.
using (var db = new SteelFrameCalculatorDataContext())
{
db.UpdateRange(modifiedProject);
db.SaveChanges();
}

Have you tried setting the state of the child object? Looks like you're only setting the parent Project state.
Adding this should do it:
db.Entry(modifiedProject.DeliveryAddress).State = EntityState.Modified;

db.Entry(modifiedProject).Reference(a=>a.DeliveryAddress).TargetEntry.State = EntityState.Modified;

Related

How do i delete single record from table using EF 6.1.1

I am using Entity Framework 6.1.1.
I am deleting single record from table as following but i am not sure whether its the only way or could further rewrite it in an efficient way.
Can someone share comments?
Reason: I am asking because many solutions in earlier posts are referring to EF 4.0 and not using the latest version 6.1.1.
Guid studentId = student.Id;
StudentReportDetail stuDetails = _context.StudentReportDetail.Find(studentId);
if (stuDetails != null)
{
_context.StudentReportDetail.Remove(stuDetails);
_context.SaveChanges();
}
There are no changes about how to delete an entity between EF 4 and EF 6. To delete an entity using Entity Framework, you need to use the Remove method on DbSet. Remove works for both existing and newly added entities.
Calling Remove on an entity that has been added but not yet saved
to the database will cancel the addition of the entity. The entity is
removed from the change tracker and is no longer tracked by the
DbContext.
Calling Remove on an existing entity that is being change-tracked
will register the entity for deletion the next time SaveChanges is
called.
Deleting with loading from the database
As the example you show in your question, you need to load first the existing entity from your context to delete it. If you don't know the Id, you can execute a query as I show below to find it first:
var report= (from d in context.StudentReportDetail
where d.ReportName == "Report"
select d).Single();
context.StudentReportDetail.Remove(report);
context.SaveChanges();
Deleting without loading from the database
If you need to delete an entity, but it’s not already in memory, it’s a little inefficient to retrieve that entity from the database just to delete it. If you know the key of the entity you want to delete, you can attach a stub that represents the entity to be deleted, and then delete this stub. A stub is an instance of an entity that just has the key value assigned. The key value is all that’s required for deleting entities.
var toDelete = new StudentReportDetail {Id = 2 };
context.StudentReportDetail.Attach(toDelete);
context.StudentReportDetail.Remove(toDelete);
context.SaveChanges();
Other way could be changing the entity's state to Deleted.DbContext has methods called Entry and Entry<TEntity>, these methods get a DbEntityEntry for the given entity and provide access to the information about the entity and return a DbEntityEntry object able to perform the action on the entity. Now you can perform the delete operation on the context by just changing the entity state to EntityState.Deleted:
var toDelete = new StudentReportDetail {Id = 2 };
context.Entry(toDelete).State = EntityState.Deleted;
context.SaveChanges();
Using a 3rd party library
There is another way but is using a 3rd party library, EntityFramework Plus, there is a nugget package you can install. You can use the batch delete operation:
context.StudentReportDetail
.Where(u => u.Id== stuDetails)
.Delete();

EF 6, adding entity to DbContext creates duplicate entity

I have a web application (MVC 5, EntityFramework 6). It's connected to an SQL database via a DbContext. I'm having an issue where adding a new entity object creates a duplicate entry in the entity set (but not the DB) and I'm not sure how to stop this from happening.
Controller, whose method is called via an ajax request:
public class CustomerController : Controller
{
MyDBEntities db = new MyDBEntities(); //DbContext
public ActionResult SaveStuff(string customerId, string stuff)
{
Customer customer = db.Single(c => c.ID.Equals(customerId));
Stuff stuff = new Stuff(stuff, customer);
db.Stuffs.Add(stuff);
db.SaveChanges();
return PartialView("MyControl", customer);
}
}
There is a 1-to-many association between Customer and Stuff, and there is a "Stuffs" navigation property in Customer.
Stuff includes fields that are int, string, and DateTime.
The controller method returns a PartialView which is used by JavaScript to refresh the contents of a control.
The "MyControl" control does this:
var stuffs = Model.Stuffs.OrderByDescending(...);
When the control is rendered in this situation, Model.Stuffs contains a duplicate entry. There's an entry with a name of Stuff (probably the new object created in the control method) as well as well as an entry with a name of System.Data.Entity.DynamicProxies.Stuff_<uuid> which is the same exact data (I imagine read from the DB).
This is only a problem when I'm writing into and then reading from an entity set within the same web request. Other/future web requests that cause a read are fine. How can I make this work correctly?
This is happening because the DateTime object is losing precision when it is written into the SQL database (see: SQL Server DateTime vs .NET DateTime). When read back from the DB, it has a different value and therefore does not overwrite the existing "stuff" object that still exists locally in db.Stuffs.
A simple solution is to change the DateTime's setter for Stuff to private and add your own pseudo-setter function that has the rounding built into it:
public void SetTimestamp(DateTime timestamp)
{
//Precision in SQL is lower than in .NET, so just round to tenth seconds
this.Updated = timestamp.AddTicks(- (timestamp.Ticks % (TimeSpan.TicksPerSecond / 10)));
}
Using DateTime2 in the SQL database (Server 2008+) is also an option should you need to maintain that level of precision.

Entity Framework 5 Foreign Key New Record on SaveChanges

I'm using .NET4.5/EF5 and have created the model from an existing database.
I'm using the following code:
Order currentOrder = new Order();
using (var db = new ILSEntities())
{
try
{
Event currentEvent = db.Events.OrderByDescending(u => u.EventID).FirstOrDefault();
currentOrder.Event = currentEvent;
db.Orders.Add(currentOrder);
db.SaveChanges();
And I'm seeing that a duplicate record is being created of the Event object I find, which is not what I wanted to happen.
I've read a lot of posts relating to similar problems, but where the context of the two participants in the foreign key relationships are different. Here, I'm saving with the same context I use to find one, and the other object is new.
I've also tried:
currentOrder.Event.EventID = currentEvent.EventID;
but that fails as well as I get an EF validation error telling me it needs values for the other members of the Event object.
I've also tried specifically setting the EntityState of the object being duplicated to Detached, Modified etc. after adding the Order object but before SaveChanges without success.
I'm sure this is a basic problem, but it's got me baffled
In my understanding, both parent and child objects have to be in the context before you assign any relationship between them to convince the entity framework that an entity exists in the database already. I guess you are trying to add new Order object to Database, to add new object you should be using AddObject method, Add() method is used to establish relation between entitties. In your code, currentOrder is not in the context. Try to hook it in the same context and then assign a relation. Your code should look like this :
Order currentOrder = new Order();
using (var db = new ILSEntities())
{
try
{
Event currentEvent = db.Events.OrderByDescending(u => u.EventID).FirstOrDefault();
db.Orders.Attach(currentOrder); //attach currentOrder to context as it was not loaded from the context
currentOrder.Events.Add(currentEvent);//establish relationship
db.ObjectStateManager.ChangeObjectState(currentOrder, EntityState.Added);
db.SaveChanges();
}
}
OK, I did in the end figure this out, and it was my fault.
The problem was that the Order object is FK'd into another table, Shipments, which is also FK'd into Events. The problem was that it was the Event reference in the Shipment object that was causing the new record. The solution was to let EF know about these relationships by adding them all within the same context.
The code assembling the object graph was spread over a number of webforms and the responses here made me take a step back and look at the whole thing critically so whilst no one of these answers is correct, I'm voting everybody who replied up

Entity framework and pure POCO update

How do I do an update on a pure POCO object using entity framework 4?
Lets say I change the person's first name and call the repository in this manner:
public User Update(User user)
{
//User originalUser = GetUser(user.UserId);
//Is there a way to update the values that are only changed?
context.Users.Attach(user);
context.ObjectStateManager.ChangeObjectState(user, EntityState.Modified);
return user;
}
I dont want null values to update the database to null. For eg. Suppose I have LastName as a property but when passing the object to the update function, it was null. Am I going to have to get the originalUser and then update each property accordingly?
"update each property accordingly?"
No, you can use,
context.ObjectStateManager.TryGetObjectStateEntry(newItem, out entity);
// this will gives you the entity present in db and after that I suggest to write your code to change the state and save.
Also suggest you to read this
for more info on tracking changes in POCO entities

How to leverage concurrency checking with EF 4.0 POCO Self Tracking Entities in a N-Tier scenario?

I'm using VS1010RC with the POCO self tracking T4 templates.
In my WCF update service method I am using something similar to the following:
using (var context = new MyContext())
{
context.MyObjects.ApplyChanges(myObject);
context.SaveChanges();
}
This works fine until I set ConcurrencyMode=Fixed on the entity and then I get an exception. It appears as if the context does not know about the previous values as the SQL statement is using the changed entities value in the WHERE clause.
What is the correct approach when using ConcurrencyMode=Fixed?
The previous values need to be in your object.
Let's say you have a property ConcurrencyToken:
public class MyObject
{
public Guid Id { get; set; }
// stuff
public byte[] ConcurrencyToken { get; set; }
}
Now you can set ConcurrencyMode.Fixed on that property. You also need to configure your DB to automatically update it.
When you query the DB, it will have some value:
var mo = Context.MyObjects.First();
Assert.IsNotNull(mo.ConcurrencyToken);
Now you can detach or serialize the object, but you need to include ConcurrencyToken. So if you're putting the object data on a web form, you'll need to serialize ConcurrencyToken to a string and put it in a hidden input.
When you ApplyChanges, you need to include the ConcurrencyToken:
Assert.IsNotNull(myObject.ConcurrencyToken);
using (var context = new MyContext())
{
context.MyObjects.ApplyChanges(myObject);
context.SaveChanges();
}
Having ConcurrencyMode.Fixed changes the UPDATE SQL. Normally it looks like:
UPDATE [dbo].[MyObject]
SET --stuff
WHERE [Id] = #0
With ConcurrencyMode.Fixed it looks like:
UPDATE [dbo].[MyObject]
SET --stuff
WHERE [Id] = #0 AND [ConcurrencyToken] = #1
...so if someone has updated the row between the time you read the original concurrency token and the time you saved, the UPDATE will affect 0 rows instead of 1. The EF throws a concurrency error in this case.
Therefore, if any of this isn't working for you, the first step is to use SQL Profiler to look at the generated UPDATE.
Mark,
The objects created as "Self-tracking entities" cannot be considered pure POCOs;
Here's the reason:
The STEs only work well if your client uses the generated proxies from the STE T4 template.
Change-tracking, and thus your service, will only work with these generated proxies.
In a pure POCO world (interoperatibility, Not all .Net 4.0 clients, .. ), you cannot put
constraints on you client. For instance, facebook will not be writing a service that can
only handle .Net 4.0 clients.
STEs may be a good choice in some environments, it all depends on your requirements.