Seeking advice for best practice
Very often I have to do the CRUD operation for a single record in my ASP.NET application.
For deletion, I was doing like
var myRecord = context.myTable.Find(myID);
if (myRecord != null)
{
context.myTable.Remove(myRecord);
context.SaveChanges();
}
Thinking about doing like
new context().myTable.Find(myID).Remove();
After reading some EF and repository pattern staff (especially Here ), I understand with the help of generic repository, at least I can do:
class UnitOfWork
{
void RemoveRecord(myRecord)
{
var context = FindMyContext(myRecord); //[here](http://blogs.msdn.com/b/alexj/archive/2009/06/08/tip-24-how-to-get-the-objectcontext-from-an-entity.aspx)
context.Entry(myRecord).State = EntityState.Deleted;
context.SaveChanges();
}
}
And I can use it like in my code:
new UnitOfWork.RemoveRecord(myRecord);
Is this a good idea?
First ask yourself what would be the added value of the repository and unit of work pattern on top of entity framework?
The context of Entity Framework already is a unit of work and already is a repository, so why create yet another one?
Also, you should create a context from the moment you need it and dispose it as soon as possible. Your service operation could look like:
public void RemoveCustomer(int customerId)
{
using(var context = new MyDbContext())
{
var customer = context.Customers.SingleOrDefault(c => c.Id == customerId);
if (customer==null) throw new BusinessException("Customer does not exist");
context.Customers.Remove(customer);
context.SaveChanges();
}
}
Personally I inject this context with a IoC framework like using StructureMap.
Related
I have something like this:
static Employee getEmployee(string ssn){
MyEntity context = null;
Employee employee;
try{
context = new MyEntity();
employee = context.Employee.Where(X => X.ssn.Equals(ssn));
}
catch (Exception exc){
LogLibrary.WriteLog(exc.Message);
}
finally{
if (context != null){
context.Database.Connection.Close();
}
}
return employee;
}
static Employee addEmployee(Employee emp){
MyEntity context = null;
Employee employee;
try{
context = new MyEntity();
context.Employee.Add(e);
}
catch (Exception exc){
LogLibrary.WriteLog(exc.Message);
}
finally{
if (context != null){
context.Database.Connection.Close();
}
}
}
And this is the code I want to implement:
Employee myNewEmployee = DBClass.getEmployee("12345");
myNewEmployee.name = "John";
DBClass.AddEmployee(myNewEmployee);
But I obviously receive the following exception: An entity object cannot be referenced by multiple instances of IEntityChangeTracker
So I've been recommended to do the following:
Employee myNewEmployee = DBClass.getEmployee("12345");
Employee myNewEmployee2 = new Employee();
// manually copy all the fields from myNewEmployee to myNewEmployee2
myNewEmployee2.name = "John";
DBClass.AddEmployee(myNewEmployee2);
But I think it might be unefficient due to the fact that I am wasting clock cycles to have an identical copy of the same object. Should we use a single static context for the whole application? (It's an ASPx project with master page). Where can I read more about "how to use contexts"? Thank you so much.
Since the code is working with completely separate DbContext instances for each call, it is technically possible to update the instance to copy and save it as a new employee after ensuring all unique values and keys are updated. However, your existing code is leaving the entity tracking references orphaned by disposing the DbContext. Code like that getEmployees should either be loading entities in a detached state with AsNoTracking() or detaching the instance from the DbContext before the context is disposed. The method can also be simplified to remove the finally block to handle disposal by using a using block:
static Employee getEmployee(string ssn)
{
using(var context = new MyEntity())
{
try
{
return context.Employee.AsNoTracking().Single(X => X.ssn.Equals(ssn));
}
catch (Exception exc)
{
LogLibrary.WriteLog(exc.Message);
}
}
return null;
}
Alternatively you can detach the entity before returning it:
try
{
var employee = context.Employee.Single(X => X.ssn.Equals(ssn));
context.Entry(employee).State = EntityState.Detached;
return employee;
}
using blocks take care of disposing instances within a scope. One missed finally block and you have an undisposed DbContext instance.
When that initial entity is not tracked by the now disposed DbContext, you can have code like:
var employee = getEmployee("12345");
employee.SSN = "54321";
employee.Name = "John";
using(var context = new MyEntity())
{
context.Employees.Add(employee);
context.SaveChanges();
}
Another alternative is to clone the entity.There are a few ways to do this including manually copying the values across or leveraging Automapper to copy the values across. This can be configured to ignore copying keys and unique values. At the very basic:
var config = new MapperConfiguration(cfg => cfg.CreateMap<Employee, Employee>());
var mapper = config.CreateMapper();
var sourceEmployee = getEmployee("12345");
var newEmployee = mapper.Map<Employee>(sourceEmployee);
newEmployee.SSN = "54321";
newEmployee.Name = "John";
using(var context = new MyEntity())
{
context.Employees.Add(newEmployee);
context.SaveChanges();
}
This code would need to ensure that the primary key value and any unique constraints are updated. If the employee table has an EmployeeId PK and that key is set up as an Identity then that should be covered automatically. Otherwise if the PK is something like the SSN you will need to ensure that is a new and unique value before saving. To do that you should first check the database to ensure the new SSN is unique:
using(var context = new MyEntity())
{
if (!context.Employees.Any(x => x.SSN == newEmployee.SSN))
{
context.Employees.Add(newEmployee);
context.SaveChanges();
}
else
{
// handle that the new SSN is already in the database.
}
}
Regarding just using a single static DbContext: No, that is not a good idea with EF. DbContexts by default track every instance they load unless explicitly told not to. This means the longer they are alive, the more instances they track, consuming memory and causing performance drops as EF will continually check across it's known tracked instances to see if it should return that rather than a new instance pulled from the database. It still runs the queries in most cases, so dealing with tracked instances does not save performance like you might think comparing the behaviour to caching. Normally you would want multiple calls though to be associated with a single DbContext instance so having the DbContext too finely scoped makes it less flexible. For example if you wanted to update a Position in a company and associate it with an employee, having a getEmployee() method that scoped it's own DBContext can actually have unintended consequences such as this example:
using (var context = new MyEntity())
{
var position = context.Positions.Single(x => x.PositionId == positionId);
var employee = getEmployee(ssn);
position.Employee = employee;
context.SaveChanges();
}
What this can end up resulting with is an error about a duplicate constraint on attempting to insert a new Employee, or it will insert a completely new clone of the Employee record. (If the Employee is configured with an Identity for it's PK) The reason for this is that the Position is being managed by one instance of the DbContext while the getEmployee() was using a completely separate DbContext instance. The position doesn't know that "employee" is an existing record and treats it like a brand new one. The proper way to ensure these instances are associated together is to ensure they are both associated with the same DbContext instance:
using (var context = new MyEntity())
{
var position = context.Positions.Single(x => x.PositionId == positionId);
var employee = context.Employees.Single(x => x.SSN == ssn);
position.Employee = employee;
context.SaveChanges();
}
Or else ensuring that both this code and getEmployee are injected with the same DbContext instance rather than scoping it within the methods. (I.e. dependency injection) Working with detached instances like your code is structured is possible but it can get quite messy so be cautious.
I am basically trying to implement CRUD using EntityFrameWork core and .Net core 3.1. I have an issue with my update operation where I am not able update the context with the modified value.
I am using postman to initiate the request.
As you can see in the code below, I am trying to check if that customer exist and if it does pass the modified object to the context.
Function code
[FunctionName("EditCustomer")]
public async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous,"post", Route = "update-customer")] HttpRequest req)
{
var customer = JsonConvert.DeserializeObject<CustomerViewModel>(new StreamReader(req.Body).ReadToEnd());
await _repo.UpdateCustomer(customer);
return new OkResult();
}
Repository method
public async Task UpdateCustomer(CustomerViewModel customerViewModel)
{
if (customerViewModel.CustomerId != null)
{
var customer = _context.Customers.Where(c => c.CustomerId.Equals(customerViewModel.CustomerId)).FirstOrDefault();
if (customer == null)
{
throw new Exception("customer not found");
}
else
{
_context.Customers.Update(_mapper.Map<Customers>(customerViewModel));
await _context.SaveChangesAsync();
}
}
}
Mapping
public class CustomerManagerProfile : Profile
{
public CustomerManagerProfile()
{
CreateMap<CustomerDetails, CustomerDetailsViewModel>().ReverseMap();
CreateMap<CustomerOrders, CustomerOrdersViewModel>().ReverseMap();
CreateMap<CustomerOrderDetails, OrderDetailsViewModel>().ReverseMap();
CreateMap<Customers, CustomerViewModel>().ReverseMap();
}
}
Solution
public async Task UpdateCustomer(CustomerViewModel customerViewModel)
{
if (customerViewModel.CustomerId != null)
{
var customer = _context.Customers.Where(c => c.CustomerId.Equals(customerViewModel.CustomerId)).FirstOrDefault();
if (customer == null)
{
throw new Exception("customer not found");
}
else
{
var customerModel = _mapper.Map<Customers>(customerViewModel);
_context.Entry<Customers>(customer).State = EntityState.Detached;
_context.Entry<Customers>(customerModel).State = EntityState.Modified;
await _context.SaveChangesAsync();
}
}
}
Entity Framework tracks your entities for you. For simplicity's sake, think of it like keeping a dictionary (for every table) where the dictionary key is equal to your entity's PK.
The issue is that you can't add two items of the same key in a dictionary, and the same logic applies to EF's change tracker.
Let's look at your repository:
var customer = _context
.Customers
.Where(c => c.CustomerId.Equals(customerViewModel.CustomerId))
.FirstOrDefault();
The fetched customer is retrieved from the database and the change tracker puts it in his dictionary.
var mappedCustomer = _mapper.Map<Customers>(customerViewModel);
_context.Customers.Update();
I split your code in two steps for the sake of my explanation.
It's important to realize that EF can only save changes to tracked objects. So when you call Update, EF executes the following check:
Is this the same (reference-equal) object as one I have I my change tracker?
If yes, then it's already in my change tracker.
If not, then add this object to my change tracker.
In your case, the mappedCustomer is a different object than customer, and therefore EF tries to add mappedCustomer to the change tracker. Since customer is already in there, and customer and mappedCustomer have the same PK value, this creates a conflict.
The exception you see is the outcome of that conflict.
Since you don't need to actually track your original customer object (since EF doesn't do anything with it after fetching it), the shortest solution is to tell EF to not track customer:
var customer = _context
.Customers
.AsNoTracking()
.Where(c => c.CustomerId.Equals(customerViewModel.CustomerId))
.FirstOrDefault();
Since customer is now not put into the change tracker, mappedCustomer won't cause a conflict anymore.
However, you don't actually need to fetch this customer at all. You're only interested in knowing whether it exists. So instead of letting EF fetch the entire customer object, we can do this:
bool customerExists = _context
.Customers
.Any(c => c.CustomerId.Equals(customerViewModel.CustomerId));
This also solves the issue since you never fetch the original customer, so it never gets tracked. It also saves you a bit of bandwidth in the process. It's admittedly negligible by itself, but if you repeat this improvement across your codebase, it may become more significent.
The most simple adjustment that you could make would be to avoid tracking your Customers on retrieval like this:
var customer = _context
.Customers
.AsNoTracking() // This method tells EF not to track results of the query.
.Where(c => c.CustomerId.Equals(customerViewModel.CustomerId))
.FirstOrDefault();
It's not entirely clear from the code, but my guess is your mapper returns a new instance of Customer with the same ID, which confuses EF. If you would instead modify that same instance, your call to .Update() should work as well:
var customer = _context.Customers.Where(c => c.CustomerId.Equals(customerViewModel.CustomerId)).FirstOrDefault();
customer.Name = "UpdatedName"; // An example.
_context.Customers.Update(customer);
await _context.SaveChangesAsync();
As a matter of fact, if you track your Customer you don't even need to explicitly call .Update() method, the purpose of tracking is to be aware of what changes were made to the entities and should be saved to the database. Therefore this will also work:
// Customer is being tracked by default.
var customer = _context.Customers.Where(c => c.CustomerId.Equals(customerViewModel.CustomerId)).FirstOrDefault();
customer.Name = "UpdatedName"; // An example.
await _context.SaveChangesAsync();
EDIT:
The solution you yourself provide begins by tracking the results of your query (the Customer) instance, then stops tracking it (a.k.a. gets detached) before writing to database and instead starts tracking the instance that represents the updated Customer and also marks it as modified. Obviously that works as well, but is just a less efficient and elegant way of doing so.
As a matter of fact if you use this bizarre approach, I don't see the reason for fetching your Customer at all. Surely you could just:
if (!(await _context.Customers.AnyAsync(c => c.CustomerId == customerViewModel.CustomerId)))
{
throw new Exception("customer not found");
}
var customerModel = _mapper.Map<Customers>(customerViewModel);
_context.Customers.Update(customerModel);
await _context.SaveChangesAsync();
You use AutoMapper wrong way. It is not created to map from View model or DTO to Entity classes. It makes many problems and you are facing with only one of them now.
If you have more complex bussiness logic in you app (not just udpate all fields), it will be horrible to manage, test and debug what actually is happening in your code. You should write you own logic with some bussiness validation in case when you want to make some other update than CRUD.
If I were you I would create UpdateFields method in Customer class which would update them and finally call SaveChanges. It depends on whether you use anemic entity (anti)pattern or not. If you do not want your entity class to have any method you can create just method which manually map you VM do entity with some domain validation
I'm trying to update Entity/model using LINQ to SQL (DBML). but I'm not able to do it.
Here is my code snippet.
public void Update(Customer customer)
{
using (MyDataContext db = new MyDataContext())
{
db.Customers.Attach(customer, true);
db.SubmitChanges();
}
}
public Customer GetByID(int ID)
{
using (MyDataContext db = new MyDataContext())
{
return db.Customers.FirstOrDefault(c => c.CustomerID == ID);
}
}
My scenario is: I get the customer object and bind the customer object to form. and after change the form input data. Data is perfectly change but when I call update method. It's not updating it and I have this error:
An entity can only be attached as modified without original state if it declares a version member or does not have an update check policy.
I searched a lots of internet but I'm not able to find any appropriate solution. I also modified my update function like that:
public void Update(Customer customer)
{
using (MyDataContext db = new MyDataContext())
{
var originalCustomer = db.Customers.FirstOrDefault(c => c.CustomerID == customer.CustomerID);
db.Customers.Attach(customer, originalCustomer);
db.SubmitChanges();
}
}
But still getting the same error.
I don't want to get Customer from database and update it properties from parameter customer properties. I want to use the same parameter customer and update it in database.
Please help me.
Thanks!
The problem is that even though you are using the same DbContext class you are using different DbContext objects because you are using two different "using" statements.
It's important that you use the same DbContext object throughout the request (assuming it's an MVC app).
The usual approach would be to instantiate the DbContext in the controller (or using Dependency Injection ) and use the reference everywhere.
The issue is you have two using statements, giving 2 different context
The easier option would be to inject it into the controller and use it when needed
public void Update(Customer customer)
{
using (MyDataContext db = new MyDataContext())
{
var originalCustomer = db.Customers.Where(c => c.CustomerID == customer.CustomerID).FirstOrDefault();
// change the originalCustomer's properties with customer's properties.
db.SubmitChanges();
}
}
I'm thinking something like this:
IUoW oUoW = oUnity.Resolve<IUoW>(); //<-- New Context here (Life per resolve).
var oNewEntity = new SomeEntity{ name = "somethink ... "};
oUoW.oSomeEntity.Add( oNewEntity);
oUoW.SaveChanges();
oUoW.Dispose();//<-- delete context.
But how can I resolve the instance for "oUoW.oSomeEntity", I could need to do a Resolve in the constructor or not...
Another way I'm thinking
IUoW oUoW = oUnity.Resolve<IUoW>(); //<-- New Context here (Life per resolve).
var oNewEntity = new SomeEntity{ name = "somethink ... "};
oSomeEntityRepository = oUnity.Resolve<ISomeEntityRepository>();//Ugly way
oSomeEntityRepository.oUoW = oUoW;//Ugly way
oSomeEntityRepository.Add( oNewEntity);
oUoW.SaveChanges();
oUoW.Dispose();//<-- Delete context.
... Open Another Context ...
That's code is not thread safe 100%, but I would short instances of context
Do you think another way?
I'll Do Unit Test now ...
To thread safe I'm thinking in another method that use a Mutex ... something like...
IUoW oUoW = oUnity.Resolve<IUoW>();
oUoW.MutexLock();
... save, delete, linq ...
oUoW.MutexUnlok();
mmm .... &%$··%&·!&$%&...mmm LAPSUS
As soon as you have your uow resolved, repositories should be direct properties of the uow:
IUoW oUoW = oUnity.Resolve<IUoW>(); //<-- New Context here (Life per resolve).
var oNewEntity = new SomeEntity{ name = "somethink ... "};
oSomeEntityRepository = uow.SomeEntityRepository;//Not ugly at all
Since most example implementations follow this idea, I wonder what your implementation is.
Anyway, it goes like
public class UnitOfWork
{
private ISomeEntityRepository _someEntityRepository;
public ISomeEntityRepository SomeEntityRepository
{
get
{
if ( _someEntityRepository == null )
_someEntityRepository = new ...
return _someEntityRepository;
}
#Wiktor Zychla is right but I his example implemetation can confuse you. If you are using a DI container, like Unity here, repositories should be injected in UOW when UOW is resolved; and a single DBContext instance injected in UOW (to call saveChanges) and in all repositores resolved (I assume that your UOW has multiple repositories becuase if not, you do not need UOW). This is know as "cascade injection" and is the butter and bread of using a DI container.
This way you can make multiple changes in Database using multiple repositories (one for aggregate root) to finish a use case and only a single UOW.Savechanges needed.
Well, I've edited a template that auto-generate a UnitOfWork, Context, Repository, And FactoryUnitOfWork http://pastebin.com/6D2X5Ykp, you need to edit the template to change the entity model if you do it in a separate dll.
To use the Pattern:
Register in Composition Root:
IUnityContainer uc = new UnityContainer();
yourdaonamespace.CompositionRoot.Init( uc );
And to use:
using (var oIUoW = this.IFactoryUnitOfWork.Resolve())
{
var YOURENTITYFoundedFromRepository = oIUoW.oRepositoryENTITY.First(o => o.iYourProperty == 1);
}
//more code
using (var oIUoW = this.IFactoryUnitOfWork.Resolve())
{
var entity = new domain.YOURENTITY()
{
sYourProperty = "TEST ENTITY"
};
uow.oRepositoryYOURENTITY.Insert(entity);
uow.Commit();
}
Requirement: Your need to generate the YOURMODEL.edmx
NOTE: The Template Is Temporal In Pastebin, Could Anyone Help With Permanent Template, Thanks!
What is the proper and fast way to save combined new and modified detached POCO entities?
I was thinking about these methods:
private void Method_2(IList<Entity> entities) //detached entities
{
//This method is using SELECT to check if entity exist
using (var context = new ModelContainer())
{
foreach (Entity entity in entities)
{
var foundEntity = context.CreateObjectSet<Entity>().SingleOrDefault(t => t.Id == entity.Id);
context.Detach(foundEntity); //Remove it from ObjectStateManager
if (foundEntity != null)//It is modified entity
{
context.AttachTo("EntitySet", entity); //Attach our entity
context.ObjectStateManager.ChangeObjectState(entity, EntityState.Modified); //We know it exists
}
else//It is new entity
{
context.CreateObjectSet<Entity>().AddObject(entity);
}
}
context.SaveChanges();
}
}
private void Method_1(IList<Entity> entities) //detached entities
{
//This method doesn't select anything from DB, but i have ta call Savechanges after each object
using (var context = new ModelContainer())
{
foreach (Entity entity in entities)
{
try
{
context.AttachTo("EntitySet", entity);
context.ObjectStateManager.ChangeObjectState(entity, EntityState.Modified);
context.SaveChanges();
}
catch (OptimisticConcurrencyException)
{
context.ObjectStateManager.ChangeObjectState(entity, EntityState.Added);
context.SaveChanges();
}
}
}
}
When you are working in detached environment you have to know which entity was added and which is modified - it is your responsibility to keep this information and provide it to ObjectContext.
Well i agree with this statement if you found yourself in situation when you need to use EF code like this in EF definitely something is wrong with you decision. I have chosen wrong tool for this job.
When you are working in detached environment you have to know which entity was added and which is modified - it is your responsibility to keep this information and provide it to ObjectContext.
The very easy way is:
foreach (var entity in entities)
{
if (entity.Id == 0) // 0 = default value: means new entity
{
// Add object
}
else
{
// Attach object and set state to modified
}
}
The example requires that you have some db auto-generated primary key (Id).
Your Method 2 is possible with some modifications. It is not needed to detach entity when you load it. Instead use ApplyCurrentValues. The approach with loading entity first is very usefull when you decide to work with object graphs instead of single entity. But in the case of object graph you have to do synchronization manually. ApplyCurrentValues works only for scalar (non navigation) properties. You can try to futher optimize your method to load needed enitites in single roundtrip to database instead of loading entities one by one.
Your Method 1 is terrible solution. Using exceptions raised on database server to control program flow is bad approach.
I agree with #Ladislav - Method_1 is a bad approach. Let the database raise exceptions which are caught by EF - don't try and swallow these exceptions yourself.
Your on the right track with Method 1.
Here is how i do it - as i also have a detached context (POCO's, no change tracking, ASP.NET MVC).
BLL Interface: (note i have TPT in my model, hence generics. "Post" is abstract)
void Add(Post post);
void Update<TPost>(TPost post) where TPost : Post, new();
The new() constraint is crucial - you'll see why shortly.
I won't show how i do "Add", because it's simple as you think - AddObject(entity);
The "Update" is the tricky part:
public class GenericRepository<T> : IRepository<T> where T : class
{
public void Update<T2>(T2 entity) where T2: class, new()
{
var stub = new T2(); // create stub, now you see why we need new() constraint
object entityKey = null;
// ..snip code to get entity key via attribute on all domain entities
// once we have key, set on stub.
// check if entity is already attached..
ObjectStateEntry entry;
bool attach;
if (CurrentContext.ObjectStateManager.TryGetObjectStateEntry(CurrentContext.CreateEntityKey(CurrentContext.GetEntityName<T>(), stub), out entry))
{
// Re-attach if necessary.
attach = entry.State == EntityState.Detached;
}
else
{
// Attach for first time.
attach = true;
}
if (attach)
CurrentEntitySet.Attach(stub as T);
// Update Model. (override stub values attached to graph)
CurrentContext.ApplyCurrentValues(CurrentContext.GetEntityName<T>(), entity);
}
}
And that works for me.
As for the entity key, i have used attributes on my domain classes. An alternative (which i'm about to move to), is have all my domain entities implement an interface, which specifies that all domain entities must have a property called "EntityKey". Then i'll use that interface on my constraints. Basically, i needed a dynamic way to create stub entities in a generic repository.
I don't personally like the idea of "checking the ID, if its > 0 then it's an update". Because i'm working with ASP.NET MVC, if i (or another developer) forgets to bind the ID to the View, it won't be passed through, so even though it may be an update, because the ID == 0 it will be added.
I like to be explicit about the operations. This way, i can perform Add/Update seperate validation logic.
Perhaps take a look at Self Tracking POCO entities. IMHO they are perfect for any scenario that requires the entity to be separated from the context. It takes care of all the plumbing code for you.