Updating issue with NHibernate - asp.net-mvc

I have Customer, CustomerGroups, Groups tables. Customer has 1:n with CustomerGroups and Groups has 1:n with CustomerGroups. In the create customer screen, user can choose the groups information of existing customer. So when I create a new customer, I am retrieving groups from existing customer and adding them
///
Customer cust = new Customer();
foreach(var item in getothercustomergroups())
cust.groups.add(item);
commit
This code is generating update statement and updating the customergroups table with newly added customerid, instead of inserting new records with new customerid. Due to this, all groups with prev. customer are gone. Could anyone please explain this behavior.

From your description, I would guess getcustomergroups has gotten customergroups from an existing customer via NHibernate. If so, NHibernate has associated each item in the foreach loop with the existing customer, so when you add item to a new customer, the new customer assumes ownership of that item.
You can avoid this by cloning the item. See How do I copy an object with NHibernate

Related

Insert new object by attaching existing entity properties in Nhibernate

We have create screens with duplicate option for each object. For ex: While creating new Customer along with details, user can chose existing customer to copy groups associated from existing to new user. So I would like to know how to assign properties of new customer for 1:n and m:n scenario.
For "Customer" and "CustomerGroups". Will the below approach work fine?
Customer existing = repo<Customer>(id);
Customer newCust = new Customer();
for(var group in existing.Groups)
newCust.CustomerGroups.Add(new CustomerGroup(){ **AllpropertiesexceptID**, **Customer=newCust** } );
For Order and OrderItems, since its m:n relationship, just attaching existing items with new order.
Orders existing = repo(id);
Order newOrder = new Order();
for(var item in existing.Items)
newOrder.Items.Add(item);
Is it required to do Session.Evict for the existing Order or Customer for performing these operations.
You might be thinking too much. :) Just go ahead and create separate lookalike objects, pretending NHibernate isn't even there. As long as the new instances have different (unset) identity properties, NHibernate won't even realize they are "copies".

Attaching an existing but modified entity to the context

In my model I have two classes Categories and Products. There is a relation many- to many between them.
I set states of all categories on modified manually and when I watched in the debugger before saveChanges() I saw that all of these categories were marked as modified. But after request mapping between categories and product weren't updated in my database. Code of update function.
public void UpdateProduct(Product product)
{
using (EFDbContext context = new EFDbContext())
{
context.Products.Attach(product);
if (product.Categories != null)
{
foreach (var item in product.Categories)
{
context.Entry(item).State = EntityState.Modified;
}
}
context.Entry(product).State = EntityState.Modified;
context.SaveChanges();
}
}
Setting entity to modified says that you have changed its properties (not navigation properties) and you want to save them. If you changed relations (navigation properties) by for example creating new relation between existing product and category or removing relation between existing product and category setting state to modified will not help you. This is actually very hard to solve (it is same in all current EF versions) because that relation has its own state which must be set and state of relation cannot be Modified = you must know if you added or removed relation. Especially removing is hard because you probably don't have information about relations you have removed from Categories navigation property when you are going to attach entity to the context. Moreover DbContext doesn't offer access to state of the relation so you must convert it to ObjectContext and use ObjectStateManager.
The easiest way to solve this issue is to load product with categories from database prior to saving and manually synchronize your detached object graph (the one you are trying to save at the moment) with loaded attached graph. Once you synchronize all changes in attached graph you will save it back to database. Attached graph will know which relations to categories were added or removed.

Update db from Excel with Entity Framework 4.1

I'm new to EF 4.1 and try to move some code from to EF 4.1 (code first). Here is some background. I'm managing products for several companies, so I have a table "Product" with a column called "Company". I need to update (insert if not exist, otherwise update) this table from an Excel file containing products for a given company(let's say C1). Here is what I'm doing (using proprietary db access code and LINQ) :
Retrieve all products for company C1 as a list of products
For each product appearing in Excel:
Search the loaded list of products if the product from Excel exists already
If product does not exist then :
create new product instance
add product to database
add product to the list of loaded products
Else
update product in database
That's pretty straightforward but converting it to EF 4.1 does not seem that easy:
I can easily retrieve and filter all products from the context. I can also easily search for the Excel product in the loaded list. If not present, I can create the product and add it to the context. But how to mimic my "caching" system where I add the newly added product to my list of product loaded in memory (Excel file can contains several times the same product) ? Also when change the entity state and when to do savechanges ?
Christian
Here is a rough outline of how you can do this.
EF caches the loaded entities. You can use Local property to access it. This collection will be modified by EF when you add new entities.
context.Products.Where(p => p.Company == "C1").ToList();//force EF to load products
while(/*loop through excel file)
{
var product = context.Products.Local.Where(p=> p.Id == excelProductId);
if (product == null)
{
//insert
}
else
{
/update
}
}
context.SaveChanges();

Entity framework many to many relation bottleneck in inserting data

i have a view that shows the user a form and the user should upload a file and choose all the categories associated with it.
the controller that is responsible in submitting the data should
retrieve the file info and
insert data in the file category
retrieve the related category ids and
insert them as well in the table
that is abstracted by the EF just
insert the file and the category ids.
this is my problem the controller just gets some info about the category not all of it. basically it only needs the ids for the insertion
i can't use
[HttpPost]
public ActionResult SaveFile(File file, List<Category> Checkbox, HttpPostedFileBase FileUpload)
{
//some stuff
//for example got the first category and named it to category1
file.Categories.Add(category1)
}
i asked someone and he told me you have to select the category you want to insert
is this really necessary ? i only need a category id and a file id to make the insert why would i fire another request to the database that i don't really need
i am using
EF 4
MVC 3
It is better to select category first because it will save you a lot of possible problems but it is not necessary. You can use dummy category object:
var category = new Category { Id = receivedId };
file.Categories.Add(category);
You will only create new category and you will set its PK. Now you need to handle file insertion where you must explicitly instruct ObjectContext to insert only file (because your categories exists in database):
context.Files.Attach(file); // now whole object graph is attached but marked as Unchanged
context.ObjectStateManager.ChangeObjectState(file, EntityState.Added); // mark only file entity as inserted
context.SaveChanges();
You can also take opposite direction:
context.Files.AddObject(file); // all objects in object graph are marked for insertion
foreach (var category in file.Categories)
{
// you don't want to insert categories again
context.ObjectStateManager.ChangeObjectState(category, EntityState.Unchanged);
}
context.SaveChanges();
This scenario works if you know that all categories exist in your database. If you want to insert new categories together with saving file you will need to query categories first or add some information about which category is new and which is existing.

How to handle relationships to users from other tables in ASP.Net MVC?

At the table level I'm setting aspnet_User.UserID as foreign key of UserID in the other tables (like Posts.UserID, so each post has an owner). Is that the way to go?
When I create the LINQ to SQL model, should I include the aspnet_User table?
When I create a post (record in the Posts table, a Post object), how do I set the relationship to the logged in user (User object in the controller)?
I don't include the aspnet_User table to my linq-to-sql as I don't really need it. I use the built in way of accessing membership data.
But for your table Posts, it might be easier for you to include it so that you can easily display the User's Name by doing myPost.User.Name
edit:
MembershipUser user = Membership.GetUser();
Guid userGuid = (Guid)user.ProviderUserKey;
Post post = new Post
{
UserId =userGuid,
Message = message
};
In your database schema, you should definately have a the UserID in the Post table be a foreign key to the aspnet_user table, on the UserID field. This way, you are making sure your data is clean. I would even add a cascade delete & update on that relationship.
Then, refer to my instructions in a previous question you asked, about how to get the user data.
(Thomas Stock summed it up briefly, above, though :) )

Resources