Getting newly added entities from ObjectContext before saving changes - nhibernate

OK, I read these:
EntityFramework show entities before saving changes
Where added objects are stored in ObjectContext?
I guess there is no clear solution of the problem (although the second post is from 2009) but I think it's an important issue of Entity Framework so I will ask my question despite all.
Let say we have code like that:
// Get somehow an UnitOfWork instance, e.g. using factory
var categoryRepository = new CategoryRepository(unitOfWork);
var newCategory = new Category("Some Category");
categoryRepository.Add(newCategory);
var allCategories = categoryRepository.GetAll();
Debug.Assert(allCategories.Contains(newCategory));
unitOfWork.Commit();
If we use NHibernate, the UnitOfWork implementation will encapsulate an ISession instance. And the given code will behave as we expect - we can get newly added category back from the repository (i.e. underlying ISession) before changes are committed.
I was surprised to discover that Entity Framework behave different. If our UnitOfWork implementation encapsulate EF's ObjectContext, the assertion fails. Before calling ObjectContext.SaveChages() (in the unitOfWork.Commit() method), newly added category is not reachable (via the same ObjectContext). I tried to find some property of ObjectContext that configure this behavior but didn't succeed.
So my question is: Is it possible to get entities from ObjectContext we just added without need of calling ObjectContext.SaveChages() (because we don't want to commit until the business transaction ends)? If the answer is "No", is not this violation of the Identity Map design pattern in particular and the UnitOfWork pattern in general? And if you use EF how deal with this scenarios?
Thanks in advance.
Sorry for the delay, guys.
It seems that you don't get my point. The question is not "How to get back this instance I've just added?" After all I have a reference to it. The question is "How does any newly added (still uncommitted - and actually it is possible never to be committed) entity to be considered by any query over the given DbSet?"
If I add a new category and then write something like that (I'm intentionally not using repository here but row DbContext (or ObjectContext if we are using EF 4.0) to be clearer to you):
var selectedCategories = context.Categories.Where(c => c.ParentCategory.Name == "Some Category Name");
I want my new category to be returned in the result set if it satisfied the condition. Probably this query will be executed in another method (or even another class) that just share the same context (repository) within single transaction (unit of work).
I know I can execute the same query over the Categories.Local, filter the result only to newly added entities (since Local contains all entities of the set that are currently being tracked) and combine it with result returned from the database. Don't you think it's terribly ugly? And I'm not even sure if I'm not missing something right now. All this is work of the ORM. It's all about transactional behavior (unit of work) and the ORM should handle it (like NHibernate does).
Now does it make sense to you?

Related

What is the best practice when adding data in one-to-many relationship?

I am developing a website for a beauty salon. There is an admin part of the website, where the esthetician can add a new care. A care is linked to a care category (all cares related to hands, feets, massages, ...). To solve this I wrote this code into the CareRepository in the .NET API :
public async Task<Care?> AddAsync(Care care)
{
// var dbCareCategory = await this._careCategoryRepository.GetByNameAsync(care.CareCategoryName);
if (string.IsNullOrEmpty(care.CareCategoryName) || string.IsNullOrWhiteSpace(care.CareCategoryName))
return null;
var dbCareCategory = await this._instituteDbContext.CareCategories
.Where(careCategory => Equals(careCategory.Name, care.CareCategoryName))
.Include(careCategory => careCategory.Cares)
.FirstOrDefaultAsync();
if (dbCareCategory == null || dbCareCategory.Cares.Contains(care))
return null; // TODO : improve handling
dbCareCategory.Cares.Add(care);
await this._instituteDbContext.SaveChangesAsync();
return care;
}
My problem here is that I am a bit struggling with the best practice to have, because in order to add a care to a category, I have to get the category first. At the first place, I called the CareCategoryRepository to get the care (commented line). But then, EF was not tracking the change, so when I tried to add the care, it was not registered in the database. But once I call the category from the CareRepository, EF tracks the change and saves the Care in the database.
I assume this is because when calling from another repository, it is a different db context that tracks the changes of my entity. Please correct me if my assumption is wrong.
So, I am wondering, what is the best practice in this case ?
Keep doing what I am doing here, there is no issue to be calling the category entities from the care repository.
Change my solution and put the AddCare method into the CareCategoryRepository, because it makes more sense to call the categories entities from the CareCategoryRepository.
Something else ?
This solution works fine, however I feel like it may not be the best way to solve this.
The issue with passing entities around in web applications is that when your controller passes an entity to serve as a model for the view, this goes to the view engine on the server to consume and build the HTML for the view, but what comes back to the controller when a form is posted or an AJAX call is made is not an entity. It is a block of data cast to look like an entity.
A better way to think of it is that your Add method accepts a view model called AddCareViewModel which contains all of the fields and FKs needed to create a new Care entity. Think about the process you would use in that case. You would want to validate that the required fields are present, and that the FKs (CareCategory etc.) are valid, then construct a Care entity with that data. Accepting an "entity" from the client side of the request is trusting the client browser to construct a valid entity without any way to validate it. Never trust anything from the client.
Personally I use the repository pattern to serve as a factory for entities, though this could also be a separate class. I use the Repository since it already has access to everything needed. Factory methods offer a standard way of composing a new entity and ensuring that all required data is provided:
var care = _careRepository.Create(addCareViewModel.CareCategoryId,
/* all other required fields */);
care.OptionalField = addCareViewModel.OptionalField; // copy across optional data.
_context.SaveChanges(); // or ideally committed via a Unit of Work wrapper.
So for instance if a new Care requires a name, a category Id, and several other required fields, the Create method accepts those required fields and validates that they are provided. When it comes to FKs, the repository can load a reference to set the navigation property. (Also ensuring that a valid ID was given at the same time)
I don't recommend using a Generic Repository pattern with EF. (I.e. Repository()) Arguably the only reason to use a Repository pattern at all with EF would be to facilitate unit testing. Your code will be a lot simpler to understand/maintain, and almost certainly perform faster without a Repository. The DbContext already serves all of those needs and as a Unit of Work. When using a Repository to serve as a point of abstraction for enabling unit testing, instead of Generic, or per-entity repositories, I would suggest defining repositories like you would a Controller, with effectively a one-to-one responsibility.
If I have a CareController then I'd have a CareRepository that served all needs of the CareController. (Not just Care entities) The alternative is that the CareController would need several repository references, and each Repository would now potentially serve several controllers meaning it would have several reasons to change. Scoping a repository to serve the needs of a controller gives it only one reason to change. Sure, several repositories would potentially have methods to retrieve the same entity, but only one repository/controller should be typically responsible for creating/updating entities. (Plus repositories can always reference one another if you really want to see something as simple as Read methods implemented only once)
If using multiple repositories, the next thing to check is to ensure that the DbContext instance used is always scoped to the Web Request, and not something like Transient.
For instance if I have a CareRepository with a Create method that calls a CareCategoryRepository to get a CareCategory reference:
public Care Create(string name, int careCategoryId)
{
if (string.IsNullOrEmpty(name)) throw new ArgumentNullException(nameOf(name));
var care = new Care { Name = name };
var careCategory = _careCategoryRepository.GetById(careCategoryId);
care.CareCategory = careCategory;
_context.Cares.Add(care);
}
We would want to ensure that the DbContext reference (_context) in all of our repositories, and our controller/UnitOfWork if the controller is going to signal the commit with SaveChanges, are pointing at the exact same single reference. This applies whether repositories call each other or a controller fetches data from multiple repositories.

Force NHibernate to get entity that is already in persisted state / 1st level cache

I have a service object that is responsible for some business logic validation. What it does, before issing Update to repository, is checking whether entity that it works on complies to some business rules.
One of that rules that is must check is if Status property of the entity didn't change when compared to entity that is in database. Because I use repositories that share the same ISession, when I try to get entity from database, in order to get an object for comparsion:
if (fromDbEntity.Status != entity.Status) throw new Exception("Cannot change status...");
I'll always get fromDbEntity that is in 1st level cache - so I work on the same object.
Is there a way to force NHibernate/Repository to get entity from database even though it's already in the scope of the session?
Evict entity from session before loading fromDbEntity
session.Evict(entity);
You can check the official documentation for more details: Managing the caches
The con about this is that you will need to manually call SaveOrUpdate for entity since now the object is out of the session.
You could, as Claudio suggests, evict the entity from the session, then load your fromDbEntity, do the comparison and then Merge the entity again with the session.
Other thing you might do is loading the fromDbEntity using the stateless session instead.
But is this really necessary? Couldn't you just make your Status property read-only? NHibernate is perfectly capable of using fields for accessing data. Or you could make your property setter protected:
public virtual Status Status { get; protected set; }
This way the user won't be able to change the property value, so there's no need to check whether current value is different from db one.
I had a similar issue, I solved it by clearing the session before any call that I want to go all the way to the data base.
session.Clear();
It's a little overkill but it works.
The way you sate your logic, it sounds like there's a potential bug. A much better solution would be to turn on dynamic-update, thus only updating changed values, then validate that no one has changed Status before saving.

Saving objects in EntityFramework over WCF causes related entities to be created

A couple of times on this current project developers have hit the same problem:
An object with related entities, i.e. an Order with a related Customer is sent back via WCF to entitywork to be saved. If the object is new we use AddObject() to put it back in the context and if it has changed, then we use ApplyCurrentValues() to update the object.
The Order object has changed, but the Customer object has not (unless the streaming via WCF affects it in some way). However, when calling SaveChanges() on the context the main object, Order in this example, is saved, but a new copy of Customer is also added to the database.
The workaround that we have found is to set the reference to Customer on Order to null before calling SaveChanges(), however this feels like a bit of a kludge.
What I'm looking for is the "correct" way to solve this problem, something akin to LazySaving = false, i.e. only save the object changed and don't try to create all the related objects.
Thanks in advance for any pointers.
I am not sure about Entity Framework, but I ran into this issue recently with NHibernate. I solved it by implementing save as follows
(1) Retrieve original entity from DB
(2) Update original entity from WCF Data Transfer object using AutoMapper
(3) Save original entity
I am not sure if you are trying to use your entities as DataContracts, in my experience its always better to use Data Transfer Objects rather than entities as you DataContract. If you dont, you continually run into all kinds of trouble, and DTO+AutoMapper gives you the control to solve most issues that you run into
http://automapper.codeplex.com/

OOP Value Objects and Entities in the same class

I am refactoring an old procedural PHP website into a tasty OOP application with a light sprinkling of Domain Driven Design for added flavour.
I keep stumbling upon cases where I have a need for classes that can have subclasses which are either entities or value objects.
An url object, for example. There are a zillion urls out there and so they all cannot really be entities. But some are very special urls, like my home page. That is an entity.
Another example is, say, a 'configuration object'. I'd like some configurations to have identities so i can create 'presets' and administer them via an online control panel. For those a finder/repository is needed to find them and ORM is needed to manage their lifetimes. But, for others 'not-presets' (of the same class hierarchy) I'd like to be able to load them up with data that has been customised on the fly and does not need to be persisted.
I am envisaging a lot of :
class factory {
reconstitute($rawdata) {
if (raw data has identity)
load up and return entity version of the class
else
load up and return anonymous/value object version of the class
It all seems a bit odd.
Is there any pattern out there that discusses the best way to handle this issue?
I'm not sure I totally understand your scenerio but... does that really matter?
In my experience with EFs/ORMs the best way (that I can think of) to do what you are wanting to do is to let your entity class decide whether or not to load/persist itself from/to a database based on business rules defined in the class.
$url = new URLClass('KEY_DATA') // returns loaded object url if key if found in database
$url = new URLClass() // returns new url object
$url = new URLClass('', '110011000110010001000011101010010100') // returns new url with data loaded from raw data
Not sure if that really helps you out or if it even applies.

Where to put NHibernate query logic?

I am trying to set up proper domain architecture using Fluent NHibernate and Linq to NHibernate. I have my controllers calling my Repository classes, which do the NHibernate thang under the hood and pass back ICollections of data. This seems to work well because it abstracts the data access and keeps the NHibernate functionality in the "fine print".
However, now I'm finding situations where my controllers need to use the same data calls in a different context. For example, my repo returns a list of Users. That's great when I want to display a list of users, but when I want to start utilizing the child classes to show roles, etc., I run into SELECT N+1 issues. I know how to change that in NHibernate so it uses joins instead, but my specific question is WHERE do I put this logic? I don't want every GetAllUsers() call to return the roles also, but I do want some of them to.
So here are my three options that I see:
Change the setting in my mapping so the roles are joined to my query.
Create two Repository calls - GetAllUsers() and GetUsersAndRoles().
Return my IQueryable object from the Repository to the Controller and use the NHibernate Expand method.
Sorry if I didn't explain this very well. I'm just jumping into DDD and a lot of this terminology is still new to me. Thanks!
As lomaxx points out, you need query.Expand.
To prevent your repository from becoming obscured with all kinds of methods for every possible situation, you could create Query Objects which make configurable queries.
I posted some examples using the ICriteria API on my blog. The ICriteria API has FetchMode instead of Expand, but the idea is the same.
I try and keep all the query logic in my repositories and try to only pass back the ICollection from them.
In your situation, I'd pass in some parameters to determine if you want to eager load roles or not and construct the IQueryable that way. For example:
GetAllUsers(bool loadRoles)
{
var query = session.Linq<Users>();
if(loadRoles)
query.Expand("Roles");
return query.ToList();
}
I would choose 2, creating two repositories. And perhaps would I consider creating another repository call to GetRoleByUser(User user). So, you could access a user's role upon user selection change on a seperate thread, if required, so it would increment your performance and won't load every user's roles for each of your users, which would require most resources.
It sounds like you are asking if it is possible to make GetAllUsers() sometimes return just the Users entities and sometimes return the Users and the roles.
I would either make a separate repository method called GetRolesForUser(User user), use lazy loading for Roles, or use the GetAllUsers(bool loadRoles) mentioned by lomaxx's answer.
I would lean toward lazy loading roles or a separate method in your repository.