One property has many photos. One photo belong to one property.
Inside my mvc controller I'm getting as parameter array of integers. These integers represents id of Photo which I want to delete.
I'm using nhibernate session and transaction to interact with db.
public ActionResult DeleteImgs(int[] data)
{
Property p = null;
using (ISession session = ....)
{
using(ITransaction transaction session.BeginTransaction())
{
Photo photo = session.Get<Photo>(data[0]);
p = session.Get<Property>(photo.Id);
// found images and delete them
foreach(int id in data)
{
Photo ph = session.Get<Photo>(id);
//remove property from association so I can delete photo
ph.Property = null;
session.Delete(ph);
session.SaveOrUpdate(ph);
}
//load property now with collection of remaining photos
// here IS THE PROBLEM, Even there is photos inside collection
// in debug I'm getting empty collection
p = session.Query<Property>().
.Fetch(x=>x.Photos).ToList() //empty?
.FirstOrDefault;
transaction.Commit();
}
}
return View();
}
Since I'm sending just IEnumrable of photos to the view problem is solved like this,
instead of sending lazy load property photos collection I'm sending IEnumerable of Photos like this
IEnumerable<Photo>photos = session.Query<Photo>().Where(x => x.Property == p).ToList();
Related
Usin ASP.NET I am trying to add a list of profiles to a object in a model and then enumerate over this list in the view.
public ActionResult Index(BlogPage currentPage)
{
var model = new BlogPageModel(currentPage);
var pages = new List<BlogPage>();
var profilePages = new List<ProfilePage>();
if (currentPage.ProfileArea != null)
{
foreach (LinkItem linkItem in currentPage.ProfileArea)
{
var page = _pageDataHelper.GetPageData(linkItem);
var profilePage = page as ProfilePage;
if (profilePage != null)
{
profilePages.Add(profilePage);
}
}
model.Profiles = profilePages;
}
return View(model);
}
Using this code in the view:
#foreach (ProfilePage profile in Model.BlogPages)
{
#Html.Partial("../ProfilePage/Index", new PageViewModel<ProfilePage>(profile))
}
However above code returns the error:
CS0030: Cannot convert type 'Models.Pages.BlogPage' to 'Models.Pages.ProfilePage'
Can someone point me the correct way to store a list inside a model and render this nested object in a view?
Thanks!
Hi Its seems that you have problem in the for each loop,but i couldn't exactly figure out the problem line, since model is not available above.
Answer to your question:
Can someone point me the correct way to store a list inside a model and render this nested object in a view?
ex:
public class somemodelname
{
public list<anytype> somepropertyname{get;set;}
}
accessing:
#foreach (var singlevalueOrObj in Model.somepropertyname)
{
#Html.Partial("../ProfilePage/Index", new PageViewModel<singlevalueOrObj >(profile))
}
In the above way you can store any list object inside your model and for rendering the page as same way as you did in the above that is using the partial view.
Hope above information was helpful.
Thanks
Karthik
You have a typo in your foreach loop:
#foreach (ProfilePage profile in Model.BlogPages)
{
#Html.Partial("../ProfilePage/Index", new PageViewModel<ProfilePage>(profile))
}
You are looping over the property BlogPages not the property Profiles that you set with a ProfilePage collection in your controller:
var pages = new List<BlogPage>();
var profilePages = new List<ProfilePage>();
if (currentPage.ProfileArea != null)
{
...shortened for length...
model.Profiles = profilePages; // Right here is what you intended to loop over
}
I've been able to integrate some scheduled web service calls into my Umbraco site that uses the response from the web service to update some of the content on my site. I can now handle text and some various other content but my main query is how should I deal with images that are delivered from the web service in byte[] format?
For a little context, the site I am developing uses web service calls to retreive the details of a product which users of our desktop software have created on their machine. Each of these products is pulled via a web service call into my Umbraco site and created as an individual product page under the parent node of products.
Products > Product
Each product has several properties such as an ID, a name, notes and a collection of images. Once I have called my web service I am creating these pages using the following code:
//Construct Service Request
svc = new StaticDataWebServiceSoapClient();
var response = svc.GetProducts(ref compressionSoapHeader,ref managedUserHeader);
//Umbraco Content Services
int rootID = 1117;
IContentService cs = ApplicationContext.Current.Services.ContentService;
var remove = cs.GetChildren(rootID).Where(x => x.ContentType.Alias == "product");
foreach (var child in remove)
{
cs.Delete(child);
}
foreach(var product in response){
var item = cs.CreateContent(product.ContinentName, rootID, "product");
//Set the properties using the SetValue method, passing in the alias of the property and the value to assign to it
item.SetValue("continentId", product.Id);
item.SetValue("continentName", product.ProductName);
item.SetValue("continentNotes", product.Notes);
foreach (var image in product.Images)
{
??? destination.SetValue("ProductImages", image._Image); ???
image.Caption;
image.FileName;
image.ImageId;
image.KeywordID;
}
cs.SaveAndPublishWithStatus(item);
}
As you can see from the code, each product has several images associated with it that I would also like to pull into the site and associate with the product page that is being created. How would I go about doing this? Would I need to use the Media Service and a specific datatype or would this structure fit easily into a multiple media picker?
You may find it easiest to loop through the images once you've retrieved them and create a new Media item for each of them, and then associate them with the product using a property based on something like the Multiple Media Picker datatype as you noted.
Because this data type stores it's values as a comma separated list of id's you could use something like the following:
// Setup
IContentService cs = ApplicationContext.Current.Services.ContentService;
var mediaService = ApplicationContext.Current.Services.MediaService;
int mediaRootId = 1111; // Replace with the id of your media parent folder
// Replace the image looping logic with the following:
// MultiMediaPicker stores it's values as a commma separated string of ids.
string imageIds = string.Empty;
foreach (var image in product.Images)
{
var fileName = image.FileName; // Assumes no path information, just the file name
var ext = fileName.Substring(fileName.LastIndexOf('.') + 1).ToLower();
if (!UmbracoConfig.For.UmbracoSettings().Content.DisallowedUploadFiles.Contains(ext))
{
var mediaType = Constants.Conventions.MediaTypes.File;
if (UmbracoConfig.For.UmbracoSettings().Content.ImageFileTypes.Contains(ext))
mediaType = Constants.Conventions.MediaTypes.Image;
var f = mediaService.CreateMedia(fileName, mediaRootId, mediaType);
// Assumes the image._Image is a Stream - you may have to do some extra work here...
f.SetValue(Constants.Conventions.Media.File, fileName, (Stream)image._Image); // Real magic happens here.
mediaService.Save(f);
imageIds += (imageIds.Length > 0 ? "," : "") + f.Id;
}
}
// Get the relevant property on the new item and save the image list to it.
var imagesProp = item.Properties.Where(p => p.Alias == "productImages").FirstOrDefault();
imagesProp.Value = imageIds;
Note - I haven't tested this code out, so ymmv.
Here is my base :
And that it contains one movie (IDs comes from an external REST API) :
Movie movie = Movie.CreateMovie(999, "MyFirstMovie");
movie.Kinds.Add(Kind.Create(123,"Adventure"));
movie.Kinds.Add(Kind.Create(124,"Comic"));
movie.Actors.Add(Person.Create(321,"John Wayne"));
movie.Directors.Add(Person.Create(120,"John Woo"));
_context.AddToMovies(movie);
_context.SaveChanges();
Now, when I'm trying to insert a new movie, I got often an exception that said that I'm inserting an entity that already exists in the base.
Suppose I got another "Adventure" movie :
// Here all data comes from an external source and have no control over it.
using(Stream stream = myExternalStream)
{
Movie movie = Unserialize(stream);
_context.AddToMovies(movie);
}
// throws the exception because the kind "Adventure" already exists
_context.SaveChanges();
How can I avoid this exception?
I think you will have the check if the Kind already exists in the DB. If yes, replace the kind in the movie.Kinds collection by the kind loaded from the database. If no, keep the deserialized kind and create a new Kind entity, for example like so:
using(Stream stream = myExternalStream)
{
Movie movie = Unserialize(stream);
var newKindList = new List<Kind>();
foreach(var kind in movie.Kinds)
{
var kindInDB = _context.Kinds
.SingleOrDefault(k => k.KindId == kind.KindId);
if (kindInDB != null)
newKindList.Add(kindInDB);
else
newKindList.Add(kind);
}
movie.Kinds = newKindList;
_context.AddToMovies(movie);
}
_context.SaveChanges();
Retrieve the movie kind, in stead of creating it each time. Or is that to obvious?
My create and delete operations are working well. But, the Edit function is giving the following error :- Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries.
NOTE:- CatPicView is a ViewModel merging the two entities Category and Picture
Following is the code for my Edit action code :-
[HttpPost]
public ActionResult Edit(CatPicView catPic)
{
if (ModelState.IsValid)
{
if (!String.IsNullOrEmpty(catPic.Picture.PictureUrl))
{
if (catPic.Category.PictureId == null)
{
Picture picture = new Picture();
picture.PictureUrl = catPic.Picture.PictureUrl;
db.Pictures.Add(picture);
catPic.Category.PictureId = picture.Id;
}
else
{
db.Entry(catPic.Picture).State = EntityState.Modified;
}
}
db.Entry(catPic.Category).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.ParentCategoryId = new SelectList(db.Categories, "Id", "Name", catPic.Category.ParentCategoryId);
return View(catPic);
}
Using the debuger, check the properties of the object you are trying to update. The most likely is that you have an ID in null.
To fix this, you should place a hidden field holding the id of the modified object so when posting the form it became mapped to your object.
You are using an ID that does not exist in the current context which is picture.Id. At the time that you are using it an ID has not yet been generated, add db.SaveChanges before attempting to use the ID.
if (catPic.Category.PictureId == null)
{
Picture picture = new Picture();
picture.PictureUrl = catPic.Picture.PictureUrl;
db.Pictures.Add(picture);
db.SaveChanges();
catPic.Category.PictureId = picture.Id;
}
So, here is my hopefully unique spin on this common problem.
I do my query, get my objects then pass the object into a form where it populates the form with the data from the object (this is not passed in by reference).
I then edit the values of the object that was queried (via the form) and then return a new object constructed from the values in the form.
I then want to update this to the database. Attach does nothing (runs but does not update). SubmitChanges also does nothing (and both do nothing when used together).
What am I missing?
Update: here is the code I am using:
// In constructor
_dataMap = new DataMapDataContext();
_addresses = _dataMap.AddressItems
.Where(address => address.InsertUserName == _currentUser.Name).ToList();
public void EditButtonClick()
{
using (AddAddressForm form = new AddAddressForm(_addresses[_currentAddress]))
{
form.Text = "Edit Address";
if (DialogResult.OK == form.ShowDialog())
{
_addresses[_currentAddress] = form.Item;
_dataMap.SubmitChanges();
DisplayItem();
}
}
}
You'll need to get the record from the database, update it's values and then call SubmitChanges()
using(MyDataContext db = new MyDataContext())
{
// get the record
Product dbProduct = db.Products.Single(p => p.ID == 1);
// set new values
dbProduct.Quantity = 5;
dbProduct.IsAvailable = false;
// save them back to the database
db.SubmitChanges();
}
Turns out I was doing almost everything right.
I just needed to pass in the object I was editing by reference. That way when it got changed, it was not a new object that was returned, but the same one (that Linq-to-SQL already knew about.)
These are the two lines from the code above that got changed:
AddressItem itemToEdit = _addresses[_currentAddress];
using (AddAddressForm form = new AddAddressForm(ref itemToEdit))