c# defer the save implementation - c#

I need assists ;-) to be honest not sure what to call it so if people come up with the more correct wording I will change the title to suit.
I have written a class for 'what ever' the class is like a utility class.. can be used in many projects across the entire app.
In the utility class.. there is a reference to the EF DB Context. This is for when i want to persist the results into the database.
I would like to remove the dependency on this being in the Utility class and rather pass in the save method.
I am struggling to figure out how you would do this. i.e. with c# Action i know you can pass in a method to be preformed i.e a pointer to a function. But how do I let that pointer know about things inside my Utility case.
I hope i worded all that correctly, please assist with either an example or link to what i am on about.
Showing code: not sure its necessary in this case. But here is a crude example.
public class UtilityCase
{
public List<Person> Persons = new List<Person>();
public void AddPerson(string name)
{
Person newPerson = new Person {Name = name};
Persons.Add(newPerson);
if (Persons.Count > 10)
{
PersistClear();
}
}
public void PersistClear()
{
//I want to be able to Set this from outside of the UtilityCase
var context = new Context();
//I want to remove the referance to the Entity (DB) Person
foreach (Person item in Persons)
{
//add person to db
}
context.saveChanges();
Persons.Clear();
}
}
DB entity case
public class Person
{
public string Name { get; set; }
}
So I understand that i would need to create a local class to the Utility to remove the reference to the Person (DB) but how do i get my function to inject to know about things inside the UtilityCase. Thanks

You need something like that?
//doesn't depends on specific Entity Data Model
public class UtilityCase
{
public List<EntityObject> Persons = new List<EntityObject>();
private readonly Action<IEnumerable<EntityObject>> _saveImpl;
public UtilityCase(Action<IEnumerable<EntityObject>> saveImpl)
{
_saveImpl = saveImpl;
}
...
public void PersistClear()
{
_saveImpl(Persons);
}
}
Call it from another project with specific Entity Data model (Context):
UtilityCase uc=new UtilityCase((col) =>
{
//I want to be able to Set this from outside of the UtilityCase
var context = new Context();
//I want to remove the referance to the Entity (DB) Person
foreach (EntityObject item in col)
{
//add person to db
context.Persons.Add((Person)item));
}
context.SaveChanges();
});
PS: not run, may contain minor errors

I am not sure exactly what you are asking but why do you need all this code and why can't you add the Person entity to the collection in Context like
var context = new Context();
context.Persons.Add(new Person {Name = name});
context.SaveChanges();
Not sure why you are maintaining an extra List<Persons> in your code. whatever, code you have shown can actually be done directly using the Persons collection present in your EF Context

Related

Entity Framework Save changes on Collection

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.

Change object type in EntityFramework

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.

Mapping entities to DTOs without duplicated code

I'm trying to get my head around this issue where I am using the Entity Framework (6) in an N-tier application. Since data from the repository (which contains all communication with the database) should be used in a higher tier (the UI, services etc), I need to map it to DTOs.
In the database, there's quite a few many-to-many relationships going on, so the datastructure can/will get complex somewhere along the line of the applications lifetime. What I stumbled upon is, that I am repeating the exact same code when writing the repository methods. An example of this is my FirmRepository which contains a GetAll() method and GetById(int firmId) method.
In the GetById(int firmId) method, I have the following code (incomplete since there's a lot more relations that needs to be mapped to DTOs):
public DTO.Firm GetById(int id)
{
// Return result
var result = new DTO.Firm();
try
{
// Database connection
using (var ctx = new MyEntities())
{
// Get the firm from the database
var firm = (from f in ctx.Firms
where f.ID == id
select f).FirstOrDefault();
// If a firm was found, start mapping to DTO object
if (firm != null)
{
result.Address = firm.Address;
result.Address2 = firm.Address2;
result.VAT = firm.VAT;
result.Email = firm.Email;
// Map Zipcode and City
result.City = new DTO.City()
{
CityName = firm.City.City1,
ZipCode = firm.City.ZipCode
};
// Map ISO code and country
result.Country = new DTO.Country()
{
CountryName = firm.Country.Country1,
ISO = firm.Country.ISO
};
// Check if this firm has any exclusive parameters
if (firm.ExclusiveParameterType_Product_Firm.Any())
{
var exclusiveParamsList = new List<DTO.ExclusiveParameterType>();
// Map Exclusive parameter types
foreach (var param in firm.ExclusiveParameterType_Product_Firm)
{
// Check if the exclusive parameter type isn't null before proceeding
if (param.ExclusiveParameterType != null)
{
// Create a new exclusive parameter type DTO
var exclusiveParameter = new DTO.ExclusiveParameterType()
{
ID = param.ExclusiveParameterType.ID,
Description = param.ExclusiveParameterType.Description,
Name = param.ExclusiveParameterType.Name
};
// Add the new DTO to the list
exclusiveParamsList.Add(exclusiveParameter);
}
}
// A lot more objects to map....
// Set the list on the result object
result.ExclusiveParameterTypes = exclusiveParamsList;
}
}
}
// Return DTO
return result;
}
catch (Exception e)
{
// Log exception
Logging.Instance.Error(e);
// Simply return null
return null;
}
}
This is just one method. The GetAll() method will then have the exact same mapping logic which results in duplicated code. Also, when more methods gets added, i.e. a Find or Search method, the same mapping needs to be copied again. This is, of course, not ideal.
I have read a lot about the famous AutoMapper framework that can map entites to/from DTOs, but since I have these many-to-many relations it quickly feels bloated with AutoMapper config code. I've also read this article, which make sense in my eyes: http://rogeralsing.com/2013/12/01/why-mapping-dtos-to-entities-using-automapper-and-entityframework-is-horrible/
Is there any other way of doing this without copy/pasting the same code over and over again?
Thanks in advance!
You can make an extension method on Entity firm (DB.Firm) like this,
public static class Extensions
{
public static DTO.Firm ToDto(this DB.Firm firm)
{
var result = new DTO.Firm();
result.Address = firm.Address;
result.Address2 = firm.Address2;
//...
return result;
}
}
Then you can convert DB.Firm object anywhere in your code like firm.ToDto();
An alternate strategy is to use a combination of the class constructor and an explicit and/or implicit conversion operator(s). It allows you to cast one user-defined entity to another entity. The feature also has the added benefit of abstracting the process out so you aren't repeating yourself.
In your DTO.Firm class, define either an explicit or implicit operator (Note: I am making assumptions about the name of your classes):
public class Firm {
public Firm(DB.Firm firm) {
Address = firm.Address;
Email = firm.Email;
City = new DTO.City() {
CityName = firm.City.City1;
ZipCode = firm.City.ZipCode;
};
// etc.
}
public string Address { get; set;}
public string Email { get; set; }
public DTO.City City { get; set; }
// etc.
public static explicit operator Firm(DB.Firm f) {
return new Firm(f);
}
}
You can then use it in your repository code like this:
public DTO.Firm GetById(int id) {
using (var ctx = new MyEntities()) {
var firm = (from f in ctx.Firms
where f.ID == id
select f).FirstOrDefault();
return (DTO.Firm)firm;
}
}
public List<DTO.Firm> GetAll() {
using (var ctx = new MyEntities()) {
return ctx.Firms.Cast<DTO.Firm>().ToList();
}
}
Here's the reference in MSDN.
About mapping: it actually does not really matter if you use Automapper or prepare you mappings completely manually in some method (extension one or as explicit casting operator as mentioned in other answers) - the point is to have it in one place for reusability.
Just remember - you used FirstOrDefault method, so you actually called the database for a Firm entity. Now, when you are using properties of this entity, especiallly collections, they will be lazy loaded. If you have a lot of them (as you suggest in your question), you may face a huge amount of additional call and it might be a problem, especcially in foreach loop. You may end up with dozen of calls and heavy performace issues just to retrieve one dto. Just rethink, if you really need to get such a big object with all its relations.
For me, your problem is much deeper and considers application architecture. I must say, I personally do not like repository pattern with Entity Framework, in addition with Unit Of Work pattern. It seems to be very popular (at least of you take a look at google results for the query), but for me it does not fit very well with EF. Of course, it's just my opinion, you may not agree with me. For me it's just building another abstraction over already implemented Unit Of Work (DbContext) and repositories (DbSet objects). I found this article very interesing considering this topic. Command/query separation way-of-doing-things seems much more elegant for me, and also it fits into SOLID rules much better.
As I said, it's just my opinion and you may or may not agree with me. But I hope it gives you some perpective here.

Move child entities to a new parent entity

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

Insert or Update with LINQ to Entity

I am trying to use Linq to Entity as my DAL for a new project.
In my DAL I have this method to get the Job Entity
public Job LoadJob(int id)
{
Job job = new Job();
using (TNEntities context = new TNEntities())
{
var jobEntity = (from c in context.Jobs
where c.id == id
select c).First();
job = (Job)jobEntity;
}
return job;
}
I use the Job entity in my program and then I would like to save it:
I have tried a few different things, but currenlt my method looks like this (it does not work)
public void SaveJob(Job job)
{
using (TNEntities context = new TNEntities())
{
context.Jobs.AddObject(job);
context.SaveChanges();
}
}
I have tried context.jobs.attach(job) which does not throw an error but it does not update my Job. I assume its because the Job is out of Context as its out of scope of the using context. But Im not sure how to re-attach it so it updates the job that I selected in my first method.
Ideally, you want to read your job from a context, make changes, then call SaveChanges on the same context you originally read it from. It might (should) be possible to attach the modified entity to a new context, and set its status to modified, but I've found modified child objects are mistreated with this approach.
One of the easier approaches is to have all of these operations in a DataAccess object that has one instance of your TNEntities context, and uses it to read your job entity, and save changes.
public class JobDao : IDisposable {
TNEntities context = new TNEntities();
public Job LoadJob(int id)
{
return this.context.Jobs.First(c => c.id == id);
}
public void Save(){
this.context.SaveChanges();
}
public void Dispose(){
this.Context.Dispose();
}
}
(of course you'll want to put a lot of that boilerplate code into a base class)
using(JobDao dao = new JobDao()) {
Job j = dao.LoadJob(12);
j.JobTitle = "Software Developer";
dao.Save();
}
I would suggest you consider leaving a property in your application.xaml.cs like
public TNEntities context {get; private set;}
which has its TNEntities initalized at startup. It will make your life easier.

Categories

Resources