I am new to NHibernate. We are using Dapper for retrieval and planning to use NHibernate for CRUD.
I am trying to remove the child object through parent list object in one to many relationship.
This works when I retrieve the object using NHibernate session and remove the item.
var mercedes = Read("chevrolet"); //queries from nhibernate session
var model = mercedes.Models.Where(c => c.Id == 181).Single();
mercedes.Models.Remove(model);
When I manually create the object and attach thecars models, it is unable to remove it.
var mercedes = new Make() { Id = 77, Name = "chevrolet" };//manually created the object
mercedes.Models = GetAllModels(77);//I have it in-memory
var model = mercedes.Models.Where(c => c.Id == 173).Single();
mercedes.Models.Remove(model);
I think I am doing something weird. But I am able to add/update the models using second approach, so why can't i remove it. Any insights please.
When you create a new domain object it isn't attached to the NHibernate session (unless you are creating a new object and call Save, for instance). As such, deleting from the models collection doesn't actually do anything.
Your second example doesn't seem like a particularly good practice but you can recreate an object and attach it to your NHibernate session using Session.Lock (Merge or Update are fairly normal depending on your preferred behavior).
Related
Code
var items = await ctx.Cartitems.Where((c) => c.Cartid == GetCartId() && c.Toodeid == product).ToListAsync();
ctx.Cartitems.RemoveRange(items);
await ctx.SaveChangesAsync();
Removes product from shopping cart in EF Core.
It isseus to commands to database: SELECT and DELETE.
How to remove items from database so that only single command is sent to server ?
ASP.NET 5 MVC Core application using EF Core with Npgsql
If you have the CartItemIds, or the IDs that make up a composite PK, then you can short-cut the delete operations by attaching a stub cart ID and marking it for deletion. Depending on the lifetime scope of your DbContext and where this call sits, you many need to check each one against the local DbContext cache before attaching.
So, assuming your UI can pass a collection of CartItemIds to flush:
// This looks for any locally loaded cart items. We will remove these rather than
// attaching stubs which would raise an exception. This doesn't hit the DB.
var localCachedCartItems = _context.CartItems.Local
.Where(x => cartItemIds.Contains(x.CartItemId))
.ToList();
// Get the IDs to exclude from the Id list to create stubs.
var localCachedCartItemIds = localCachedCartItems
.Select(x => x.CartItemId)
.ToList();
// Build stubs for the remaining cart items.
var cartItemsToRemove = cartItemIds.Except(localCachedCartItemIds)
.Select(id => new CartItem { CartItemId = id })
.ToList();
foreach(var stub in cartItemsToRemve)
{
_context.Attach(stub);
_context.Entity(stub).State = EntityState.Deleted;
}
_context.SaveChanges();
If you are using locally scoped DbContexts (I.e. /w using blocks) then you can skip the Local check and just create the stubs:
using(var context = new AppDbContext())
{
var cartItemsToRemove = cartItemIds
.Select(id => new CartItem { CartItemId = id })
.ToList();
foreach(var stub in cartItemsToRemve)
{
_context.Attach(stub);
_context.Entity(stub).State = EntityState.Deleted;
}
context.SaveChanges();
}
Entity Framework primarily works as a change tracker, that records changes to tracked entities which are then executed and committed when calling SaveChanges. But in order to track changes like a removal, it needs to actually track those entities first. And for that, it needs to query those from the database to know which entities actually exist.
If you only want to delete entities by their primary identifier, then you could use some low-level stuff by attaching fake entities to the change tracker and then removing those, which causes EF to delete the objects from the database. Things like this require some more internal knowledge though and are not really easy to understand. So I’d recommend you to avoid approaches like these.
What you can do is use an extension that offers bulk updates on top of Entity Framework. These will usually go aroud the change tracker (meaning that the changes are executed immediately) and do not require you to load the entities into the context first. There are a few libraries that do this:
Entity Framework Extensions, a paid library with advanced functionality.
Entity Framework Plus, the free community version of EF Extensions. (GitHub)
EFCore.BulkExtensions
The code below returns a single record from my database, as-expected. However, it fails to track changes in the UI. I'm binding myObject's properties to various fields using angularjs. Everything initially loads fine, but if I make changes to the object and use breeze's EntityManager.saveChanges(), it doesn't detect than anything has changed. I can create a new entity and save it just fine, but trying to understand how to handle updates. Do I need to detach the entity after I retrieve it, then reattach and save?
Or is this the wrong way to assign a retrieved entity to my javascript (using TypeScript) object?
myObject = data.results[0];
let query = breeze.EntityQuery.from("myTable").where('id', '==', incomingId).expand(['relatedTable']);
dataService.executeQuery(query).then((data) => {
this.myObject = data.results[0];
});
I had to add '.toType("myType")' clause onto the query. I used 'metadataStore.registerEntityTypeCtor' to register my types in the EntityManager, but this step was still necessary for me, which I don't entirely understand.
let query = breeze.EntityQuery.from("myTable").where('id', '==', incomingId).expand(['relatedTable']).toType("myType");
dataService.executeQuery(query).then((data) => {
this.myObject = data.results[0];
});
Edit: I also found that using the EFContextProvider to do my querying improved my results and lessened issues incredibly. In the past, I had only used the Context, and while it worked, my entity types were not understood as well by Breeze on the client side.
readonly EFContextProvider<Context> _contextProvider = new EFContextProvider<Context>();
[HttpGet]
public IQueryable<Dispute> Disputes()
{
return _contextProvider.Context.Disputes;
}
I have this code in a Windows Service targeted to .Net 4.5 that uses a database-first Entity Framework layer:
var existingState = DataProcessor.GetProcessState(workerId);
existingState.ProcessStatusTypeId = (int)status;
existingState.PercentProgress = percentProgress;
existingState.ProgressLog = log;
DataProcessor.UpdateProcessState(existingState);
And this code in a data processing class in the same solution:
public ProcessState GetProcessState(int id)
{
using (var context = new TaskManagerEntities())
{
var processes = (from p in context.ProcessStates.Include("ProcessType").Include("ProcessStatusType")
where p.IsActive && p.ProcessStateId == id
select p);
return processes.FirstOrDefault();
}
}
public ProcessState UpdateProcessState(ProcessState processState)
{
using (var context = new TaskManagerEntities())
{
context.ProcessStates.Add(processState);
context.Entry(processState).State = System.Data.EntityState.Modified;
context.SaveChanges();
}
return processState;
}
ProcessState is a parent to two other classes, ProcessStatusType and ProcessType. When I run that code in the windows service, it retrieves a record, updates the entity and saves it. Despite the fact that the ProcessType child is never used in the above code, when the save on the ProcessState entity is performed, EF does an insert on the ProcessType table and creates a new record in it. It then changes the FK in the ProcessStatus entity to point it at the new child and saves it to the database.
It does not do this in the ProcessStatusType table, which is set up with an essentially identical FK parent-child relationship.
I now have a database full of identical ProcessType entries that I don't need, and I don't know why this is occurring. I feel like I'm making some obvious mistake that I can't see because this is my first EF project. Is the issue that I'm allowing the context to expire in between calls but maintaining the same entity?
Using Add will set the state of all elements to Added, which is causing the child elements to be inserted. The parent element is not inserted as you specify EntityState.Modified for this element.
Try using the following in the UpdateProcessState rather than using Add.
context.ProcessStates.Attach(processState);
context.Entry(processState).State = EntityState.Modified;
context.SaveChanges();
Attach will set the state of all elements to Unchanged and by specifying Modified for the parent element you are indicating that only this element should be updated.
On another note. You should use the strongly-typed Include(x => x.ProcessType) rather than Include("ProcessType").
I am trying to find the best way to generate an enities, this is what I am doing at the moment.
I create an entity trough a mapper and a hydrator like this:
namespace Event\Model\Mapper;
use ZfcBase\Mapper\AbstractDbMapper;
class Event extends AbstractDbMapper
{
protected $tableName = 'events';
public function findEventById($id)
{
$id = (int) $id;
$select = $this->getSelect($this->tableName)
->where(array('event_index' => $id));
$eventEntity = $this->select($select)->current();
if($eventEntity){
//Set Location Object
$locationMapper = $this->getServiceLocator()->get('location_mapper');
$locationEntity = $locationMapper->findlocationById($eventEntity->getLocationIndex());
$eventEntity->setLocationIndex($locationEntity);
//Set User Object
$userMapper = $this->getServiceLocator()->get('user_mapper');
$userEntity = $userMapper->findUserById($eventEntity->getEnteredBy());
$eventEntity->setEnteredBy($userEntity);
//Set Catalog Object
$catalogMapper = $this->getServiceLocator()->get('catalog_mapper');
$catalogEntity = $catalogMapper->findCatalogById($eventEntity->getCatalogIndex());
$eventEntity->setCatalogIndex($catalogEntity);
}
return $eventEntity;
}
}
Now the problem with this approach is that when I call let say the User entity this entity has other entities attach to it so when I generate the Event entity by inserting the User entity my Event entity becomes very large and bulky, I dont want that I just want the first layer of the "gerontology tree".
So I was thinking on creating a EventEntityFactory where I can bind together the child entities of the Event enity, I was planning on doing a factory for this.
Is there a better way of doing this?
Thanks
One approach would be to use Virtual Proxies (with lazy loading):
http://phpmaster.com/intro-to-virtual-proxies-1/
http://phpmaster.com/intro-to-virtual-proxies-2/
Basically you would generate your entity, and replace any related entities with a light weight proxy object. this object would only load the related entity when required via lazy loading.
I've used this approach many times along with the Datamapper design pattern and it works very well.
I am new to MVC, so please excuse me if my question sounds silly or too simple. I am using Entity Data Model for database access. So in my Models folder, I have added an EDMX file and I can access the model classes from my controllers and strongly typed views. The problem arises when I access more than one table in my controller e.g.
If I have following tables in my DB :
Departments(DepartmentID, DepartmentName, DepartmentPhone)
Insurances(InsuranceID, InsuranceName, InsuranceAddress)
Employees(EmployeeID, EmpFName, EmpLName, DepartmentID, InsuranceID)
And I want to display a list of Employees with their department and insurance information.
In my Controller's Action Method I access the DB using EDM and get the information in an anonymous type:
using (var context = new MyEntities())
{
var model = (from d in context.Departments
join e in context.Employees on d.DepartmentID equals e.DepartmentID
join I in context.Insurances on I.InsuranceID equals e.InsuranceID
select new
{
DepartmentID = d.DepartmentID,
EmployeeID= e.EmployeeID,
EmpFName= e.EmpFName,
EmpLName= e.EmpLName,
DepartmentName= d.DepartmentName,
InsuranceName= I.InsuranceName
}).ToList();
return View(model);
}
I don't have a class of this anonymous type in my Model folder so I can't create a strongly typed view. So what is the best way to pass this list to the View?. Using viewbag will be an overkill if the collection is too large. Creating a new Model for this anonymous class doesn't sound right as it needs to be updated all the time if I change my selection in Controllers Action Method.
All suggestions are welcomed. I tried looking through other questions on SO but couldn't find anything relevant.
Thanks.
I don't have a class of this anonymous type in my Model folder so I
can't create a strongly typed view
Right click on your project, Add New Class ... and now you have a type in your Model folder. This is the way to go in ASP.NET MVC => view models.
And then obviously you pass this type to your view:
select new MyViewModel
{
DepartmentID = d.DepartmentID,
EmployeeID = e.EmployeeID,
EmpFName = e.EmpFName,
EmpLName = e.EmpLName,
DepartmentName = d.DepartmentName,
InsuranceName = I.InsuranceName
}).ToList();
And of course now your view becomes strongly typed to this view model:
#model IEnumerable<MyViewModel>
...
I'm afraid that predefined strongly-typed ViewModels are the way to go. It is a pain to have to update seemingly duplicate code in multiple places but in my experience it's only a problem for smaller projects. As the project grows you begin to see differences between database model objects (entities) and the viewmodels passed to your views, such as Validation and processing attributes and view-specific data, and when you get to that point you begin to prefer having separate Entity and ViewModel definitions.
However, back on-topic: an alternative solution to your problem is to use reflection to convert an anonymous type into a Dictionary<String,Object> object. Note that ASP.NET MVC does this for converting new { foo = "bar" }-syntax expressions into dictionaries for Route Values and HTML attributes already. Performance is acceptable, but don't try to do it for 10,000 objects for a single HTTP request otherwise you might get bogged down.
Here's what the code for that would look like:
Object anonymousType = new { whatever = "foo" };
Dictionary<String,Object> dict = new Dictionary<String,Object>();
foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(anonymousType )) {
Object value = descriptor.GetValue(anonymousType );
dict.Add( descriptor.Name, value );
}
Of course this means that your Views won't benefit from compile-time type-checking and you'll have to maintain a documented list of dictionary keys (assuming you aren't iterating over keys in your view).
I'll note that I am surprised Microsoft didn't make anonymous types automatically implement IDictionary because it seems natural.
dynamic type is your friend.
You can declare your view as loosely typed, having a dynamic as your model
#model dynamic
You will access model properties as you do in strongly typed view
<h1>Model.DepartmentId</h1> - <h2>Model.DepartmentName</h2>
<span>Model.EmployeeId</span>
The problem thought, that dynamics contains internal properties, if you are using MVC2 you need a little trick to make it work. But seems for MVC3 and higher, it's not longer required.