What is the best way to move child entities from one parent entity to another? Is there a method inside the ObjectContext or DbContext that allows us to accomplish this?
public class Person
{
public int PersonId
public ICollection<Car> Cars
}
public class Car
{
public int CarId
public string Color
}
EDIT: I'm currently using EF 4.0 model first with POCO template.
I'd say what you want to accomplish is changing the owner of the car in this example. If there are no serious cons against adding a back reference to Person in the Car i'd go with something like:
public class Car
{
...
public virtual Person Owner { get; protected set; }
public void ChangeOwner(Person newOwner)
{
// perform validation and then
Owner = newOwner;
// maybe perform some further domain-specific logic
}
}
NOTE: the protected setter is to enforce calling the ChangeOwner method by external consumers. EF wil be able to set it properly thanks to the autogenerated proxies for POCO classes (assume you use them).
EDIT:
In case there is no possibility to add a back reference to Person, you still have have the same goal looking from the domain logic perspective. You just want to change owner of a car. Such operation involves two entites so i'd probably go with a method placed somewhere outside the entity (regardless of where it should be placed in a well designed system):
public void ChangeCarOwner(Person originalOwner, Person newOwner, int carId)
{
Car car = originalOwner.RemoveCarOwnership(carId);
newOwner.AddCarOwnership(car);
}
public class Person
{
...
public Car RemoveCarOwnership(int carId)
{
Car car = this.Cars.Single(c => c.Id == carId);
this.Cars.Remove(car);
return car;
}
}
This is just a conceptual piece of code and it most certainly can be written better (making sure the old owner actually owns the car etc.), but i just wanted to present an idea of how would i approach it. I also ommited the implementation of AddCarOwnership cause i suppose it's pretty strainghtforward. I introduced those methods cause adding and removing ownership may trigger some further logic "inside" a particular person.
With modern EFCore, you can do this very simply by Attaching the new Parent entity, which contains Children with IDs in them. It will reassign the FK of the child (or create it if no ID is specified), and create the new Person, all in one go
Ex:
var newOwner = new Person {
Cars = new List<Car> {
new Car { carId = theCarToMove.carId }
}
};
Context.Attach(newOwner);
await Context.SaveChangesAsync();
Beware that Attach can cause problems if your Context isn't truly transient, but as a bandaid you could always clear the ChangeTracker before attempting an Attach
EDIT: After trying this, I found that for some DB providers, it doesn't work directly. Instead, try:
foreach(var car in carsToMove)
{
Context.Attach(car);
car.Owner = newOwner;
}
Context.Attach(newOwner);
await Context.SaveChangesAsync();
Order matters when using Attach. The SQL query built by EFCore builds in reverse of the order you set it up in C#. If you attach the newOwner before the cars, the CREATE query is the last thing in the SQL, after the UPDATE for the cars. If this is the case, the cars can't UPDATE to the new OwnerId, because the newOwner did not have an ID at that point in the query. I believe this is also what's happening with the first code block, with some providers
Related
I have the following entity:
class Car
{
public string make;
public string model;
public string registration;
}
We have multiple dealerships and we want to ensure that dealer1 can only see cars that belong to them, and dealer2 can only see their cars.
We don't want to implement this check in the everyday business logic of our applications since it could lead to inconsistent enforcement of the rules, so I'm creating a thin wrapper around Entity Framework which does that.
I have another entity:
class Dealer
{
public Guid id;
}
I don't want car to reference dealer, so instead I plan to have my wrapper code look like this:
void AddCar(Car car, Dealer dealer)
{
// Some authorization logic goes here
*Add dealer if not already added
context.Add(car)
*Add link between car and dealer to third table
}
Is there any way to add data to a third link table without defining a new class to represent that link for every type of entity? E.g. can I just do like a dumb table insert or something like that?
I've tried to simplify my example as much as possible for clarity, but the reality is that I'm trying to make the wrapper generic as I have no idea what entities exist across all the micro services it will be used in (and nor should I)
You can execute SQL queries in entity framework by using ExecuteSql.
int carId = 1;
int dealerId = 1;
using (var context = new AppDbContext())
{
var sql = $"INSERT INTO [CarDealer] ([CarId], [DealerId]) VALUES ({carId}, {dealerId})";
var rowsModified = context.Database.ExecuteSql(sql);
}
I have this piece of code
public int Update(Item item)
{
using (var ctx = new DataConext())
{
ctx.Entry(item).State = EntityState.Modified;
return ctx.SaveChanges();
}
}
Class Item
{
public string Name {get;set;}
public ICollection<Foobar> Foos {get;set;}
}
Class Foobar
{
public string FirstName {get;set;}
public string LastName {get;set;}
}
Lets say:
item.Foos.ElementAt(0).FirstName = "edited name"
SaveChanged() is executed but I have the 'old' values on the database and not 'edited name'...
I can see the correct changes in Local in debug.
Looks like your object came from a different context that the one you are using now. In that case you can't do that with a generic because you need to do a foreEach in your Foobar collection and change the state for each item individually.
What you have here is a disconnected entity graph so the entity is disconnected and change tracking is lost. You only set the state of the main entity and so EF assumes that everything else is unchanged.
Jullie Lerman's books is a good source to understand how this works
What I would do is I would keep this method for simple entities but make it virtual so you can inherit this repo to create specific entity repos and override the update method with a more specific implementation suitable to an entity like the one in your example.
An article that helped my to design such a repo was this: http://www.asp.net/mvc/overview/older-versions/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application.
You are loading the object in a context and saving in another. Remove using (var ctx = new DataConext()) block, and search for a way to reach the context that loaded the item, then call SaveChanges(); Another way is pass the context to the method, like this public int Update(Item item, DbContext context) and save the changes.
Class Item
{
public string Name {get;set;}
public ICollection<Foobar> Foos {get;set;}
}
You need Include to include the Foos to the object manager. Right now, it is eager loading. Wherever you are loading the item, you have to include it.
You should use include, or you can use virtual to have them lazy load.
I'm working on a desktop application using C# and EF6.
For some reasons (One would be the complexity of the structure of the models) I've decided to use only on DbContext for the whole project, instead of create and dispose every time I need to add, update, delete or fetch any data.
Let's say I have 2 Models
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
}
public class CollegeStudent : Student
{
public string Course { get; set; }
}
I have an ObservableCollection in the ViewModel and instantiate it after I add an item to the collection.
I add and Student object to the database in the following way
public void AddStudent()
{
var obj = new Student() { Name = "Mike" };
_context.Set<Student>().Add(obj);
StudentCollection = new ObservableCollection<Student>(_context.Set<Student>().ToList());
}
And when I want to change the type of the Student to the CollegeStudent I use the following piece of code
public void AddCollegeStudent(CollegeStudent obj)
{
var original = _context.Set<Student>().Find(obj.Id);
var obj = new Student()
{
Id = original.Id,
Name = original.Name,
Course = "Some Course",
}
_context.Database.ExecuteSqlCommand("INSERT INTO CollegeStudent (Id, Course) VALUES (obj.Id, '" + obj.Course + "');");
StudentCollection = new ObservableCollection<Student>(_context.Set<Student>().ToList());
}
It perfectly works and insert the CollegeStudent details in the database but when getting the list of students from the database it throws the following
exception:
All objects in the EntitySet 'Students' must have unique primary keys. However, an instance of type 'CollegeStudent' and an instance of type 'Student' both have the same primary key value, 'EntitySet=Students;Id=4'
I've decided to use only on DbContext for the whole project, instead of create and dispose every time I need to add, update, delete or fetch any data.
There's your problem...
This is one reason why you shouldn't you a single DbContext for an entire app - changes to underlying data can make the data in your context invalid. Contexts are meant to be created and disposed with every DB operation. They are lightweight so creating lots of them shouldn't be a big problem.
I realise you are likely trying to keep things as straightforward as possible but it might be worthwhile separating your concerns sooner rather than later.
Assuming this is a XAML UI you could make use of a framework like MVVM Light or Prism
https://mvvmlight.codeplex.com
https://msdn.microsoft.com/en-us/library/ff648465.aspx
If not the basics are you want some kind of mediator (http://www.blackwasp.co.uk/mediator.aspx)
So the idea is you will have some kind of service class that makes a call to save the data, then raises the message/event saying that the data was updated.
You would register a handler for when that event is raises to update the view model accordingly.
Hope this makes sense.
I've been trying to find a flexible way of exposing an object through a 'view'. I'm probably better off explaining by way of example.
I have an Entity Framework entity model, and a web service that can be used to query it. I am able to return the entity classes themselves, but this would include some fields I might not want to share - IDs, for examples, or *Reference properties from any associations in the entity model.
I figure what I need is a view of the data, but I don't particular want to write a view wrapper class for every return type. I'm hoping I'll be able to define an interface and somehow make use of that. For example:
interface IPersonView
{
string FirstName { get; }
string LastName { get; }
}
-
// (Web service method)
IPersonView GetPerson(int id)
{
var personEntity = [...];
return GetView<IPersonView>(personEntity);
}
However, in order to do something like this, I'd have to have my entities implement the view interfaces. I was hoping for a more flexible 'duck-typed' approach as there may be many views of an object, and I don't really to want to have to implement them all.
I've had some success building a dynamic type by reflecting the interface and copying fields and properties across, but I'm not able to cast this back to the interface type in order to get strong typing on the web service.
Just looking for some comments and advice, both would be welcome. Thanks.
You shouldn't ever really be passing entities directly out to a client, they should be used for persistance only. You should introduce DTOs/POCOs tailored to whatever data your API wants to return e.g.
public class PersonDto
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
// public API method
public PersonDto GetPersonApi(int id)
{
var personEntity = // pull entity from db
return new PersonDto()
{
FirstName = personEntity.FirstName,
LastName = personEntity.LastName
};
}
This keeps a clean separation between your persistence layer & public interface. You can use a tool like AutoMapper to do the legwork in terms of mapping the data across. Just setup a mapping once e.g. in your global asax:
protected void Application_Start()
{
Mapper.CreateMap<Person, PersonDto>();
}
...
// public API method
public PersonDto GetPersonApi(int id)
{
var personEntity = // pull entity from db
return Mapper.Map<Person, PersonDto>(personEntity);
}
I typically see this done with AutoMapper or a similar tool. It makes mapping between similar classes much simpler. You still have to create the Views (which in an MVC-context would be a Model), but the most tedious part (the mapping) is taken care of for you so long as you use the same field names.
As a side note, sharing IDs and other reference data will be necessary if you want to update the data, since you'll need to know the keys in order to know which record(s) to update.
I am having some problem about how to work with an entity say an EF entity and a surrogate type, which will be bound to the UI.
Suppose that I have following classes
// Db Entity
public class Car
{
public virtual int Id { get; set; }
public string ChassisNumber { get; set; }
public virtual string Brand { get; set; }
public virtual string Name { get; set; }
}
// Surrogate type that reflects some properties of Car entity
// This class will be bound to UI
public class SurrogateCar
{
public string Brand { get; set; }
public string Name { get; set; }
}
Now I will be getting List<Car> from db and want to create a List<SurrogateCar> that represents my entities. I can do this easily in many ways, one of them like this:
List<Car> cars = CarTable.GetMyCars(); // Just a dummy method, suppose it returns all entities from Db.
List<SurrogateCar> surrogates = new List<SurrogateCar>();
foreach (var car in cars)
{
surrogates.Add(new SurrogateCar { Brand = car.Brand, Name = car.Name });
}
or I can write a custom cast method. But what I worry about is the performance. This method will be called frequently, so creating a list and populating it one by one seems a potential problem to me.
Do you have any better ways to do this, or is it okay to use it like this?
Thanks.
If you have a web service, and that service is always going to return the SurrogateCar class, then you can write your entity query to return the class you want rather than getting the class you don't want:
var cars = from c in context.Cars where {your condition}
select new SurrogateCar
{
Brand=c.Brand,
Name=c.Name
};
If, on the other hand you need the list of cars all the time, then as Roger pointed out AutoMapper is great! You just call
CreateMap<Car, SurrogateCar>
then you just use Automapper to populate your new list:
surrogates.AddRange(Map<IEnumberable<Car>, IEnumerable<SurrogateCar>>(cars));
Don't worry about the performance until you've really measured that's your bottleneck! Most probably these mappings between different types aren't that slow.
There are tools out there, eg AutoMapper
http://automapper.org/
It's main purpose isn't performance though, but to potentially makes you write easier and less code.
I believe what you are really looking for is AutoMapper, it allows for seamless, easy code written around this situation. I would not worry too much about the performance unless you need to worry about it.
Here is a SO about mapping lists using automapper, also