nhibernate sessions - asp.net-mvc

Entity Photos belongs to Property entity and one property can have many photos. Mapping is fine, creating data is doing ok. In db my photos are stored for example
Id 1 binarydata PropertyId(100)
And Property article with Id of 100 have reference to many photos. I'm write all this to say that my creation of data is ok and mapping as well.
So, the problem is on loading photo collection on showing property details.
I need to load photo collection inside session, so I'm stuck here.
public ActionResult Details(int id)
{
MyDomain.Property data = null;
using (//session)
{
using (//transaction)
{
data = session.QueryOver<MyDomain.Property>()
.Where(x => x.Id == id)
.Fetch(x => x.Photos).Eager //empty
.Fetch(x => x.Features).Eager
.SingleOrDefault<MyDomain.Property>();
//I was thinking here to call
// data.Photos = GetMyPhotos(id);
tx.Commit();
return PartialView("_HomePageDetailsPartial", data);
}
}
//return PartialView("_HomePageDetailsPartial", data);
}
As you can see in this I tried with data.Photos = GetMyPhotos(id); but on debug I have Error message Cannot update identity column 'Id'.Cannot update identity column 'Id'.
Even this work, I'm convinced that there is some more elegant way to retrieve photos collection for particular property.
My mappings
public class PhotoMap : ClassMap<Photo>
{
public PhotoMap()
{
Table("Photo");
Id(x => x.Id).GeneratedBy.Identity();
Map(x => x.ImageData).CustomSqlType("VARBINARY(MAX)").Length(160000).Not.Nullable();
Map(x => x.ImageMimeType).Not.Nullable();
References(x => x.Property).Column("PropertyId");
}
}
public class PropertyMap : ClassMap<Property>
{
public PropertyMap()
{
Table("Property");
Id(x => x.Id).GeneratedBy.Identity();
...
References(x => x.Features, "FeaturesId");
HasMany(x => x.Photos).KeyColumn("Id").Cascade.All();
}
}
DB snapshot
Two tables, Property and Photo.
Id int not null
Title nvarchar(255) not null
PhotoId int not null
Photo table
Id int not null
ImageData varbinary(MAX) null
ImageMimeType varchar(50) null
PropertyId int not null
Relationship is as follows:
FK_Property_Photo
Primary Key table Foreign key table
--------------------------------------------
Photo Property
--------------------------------------------
Id PhotoId

your KeyColumn in your mapping is wrong. KeyColumn is used to define the foreign key column in the n-table. In your case, the key column should be "PropertyId".
in addition: why do you have a PhotoId column in your property table if the relation between property and photo is 1:n?

Related

return relational data list to partial view

I wanted to return a list to my partial view from relational matching data of products. I have attached picture of edmx file where you will get idea about their relationship status! Problem is i just dont know how can i write this query or i need any iteration process to do it. Main goal is: I want to get all Products that the current user has bookmarked. Any question welcome. Thanks in advance
[ChildActionOnly]
[Authorize]
public PartialViewResult _UserBookmark(string id)
{
using (mydb db = new mydb())
{
int userId = db.Users.Where(x => x.Email == id).FirstOrDefault().UserId;//here i am getting user primary key id
var ProductIds = db.Bookmarks.Where(x => x.UserId == userId).ToList();//here i am getting all Product primary keys under that user
var ListOfProducts = db.Products.Where(x=>x.ProductId == "i dont know how to do it") // here i wanted to return matched all products
return PartialView("_UserBookmark",ListOfProducts);
}
}
You can use a .Contains statement to return the Products where the ProductId is in your collection of ProductIds.
Change the method to
[ChildActionOnly]
[Authorize]
public PartialViewResult _UserBookmark(string id)
{
using (mydb db = new mydb())
{
int userId = db.Users.Where(x => x.Email == id).FirstOrDefault().UserId;
// Get a collection of the ProductId's
IEnumerable<int> ProductIds = db.Bookmarks
.Where(x => x.UserId == userId).Select(x => x.ProductId);
IEnumerable<Product> ListOfProducts = db.Products
.Where(x => ProductIds.Contains(x.ProductId))
return PartialView("_UserBookmark", ListOfProducts);
}
}
Note, if the results are for the current user, then consider just getting the current user in the method rather that passing their Email to the method. Note also that .FirstOrDefault().UserId would throw an exception is you passed an incorrect value to the method which resulted in User being null.

IQueryable to IEnumerable

public IEnumerable<Temp_Order> Get_Temp(string id)
{
//List<Temp_Order> data = new List<Temp_Order>();
IEnumerable<Temp_Order> data = db.Temp_Order
.Join(db.Items,
t_id => t_id.ItemId,
I_id => I_id.ItemId,
(t_id, I_id) => new { t_id.Quantity, I_id.ItemName })
.Where(x => x.ItemName == id);
return data;
}
In this method I want IEnumerable<Temp_Order>. So I will use this in controller and return to the view.
I'm getting this error:
Cannot implicitly convert type 'System.Linq.IQueryable' to 'System.Collections.Generic.IEnumerable'. An explicit conversion exists (are you missing a cast?) E:\WORK\Projects\RMS_Live\RMS_Live\Models\Order.cs
The Join is converting your query to an IEnumerable of an anonymous type. Add a Select on the end to cast is back to Temp_Order:
public IEnumerable<Temp_Order> Get_Temp(string id)
{
//List<Temp_Order> data = new List<Temp_Order>();
IEnumerable<Temp_Order> data = db.Temp_Order
.Join(db.Items, t_id => t_id.ItemId, I_id => I_id.ItemId, (t_id, I_id) => new { t_id.Quantity, I_id.ItemName })
.Where(x => x.ItemName == id)
.Select(a => new Temp_Order
{
ItemName = a.ItemName,
Property2 = a.Property2,
//snip
});
return data;
}
EDIT:
You indicate in the comments that you want all properties from both Temp_Order and Item which means you need another class. You can get away without creating another class, but it's much simpler in the long run. So first make your class, 2 ways spring to mind, you either replicate all the properties you need or just return the 2 objects, I'll use the latter:
public class OrderItem
{
public Temp_Order Temp_Order { get; set; }
public Item Item { get; set; }
}
Now your function becomes this:
public IEnumerable<OrderItem> Get_Temp(string id)
{
IEnumerable<OrderItem> data = db.Temp_Order
.Join(db.Items,
t_id => t_id.ItemId,
I_id => I_id.ItemId,
(t_id, I_id) => new OrderItem
{
Temp_Order = t_id,
Item = I_id
})
.Where(x => x.ItemName == id);
return data;
}
And in your view, make sure you set the model type to IEnumerable<OrderItem> and you can access all the properties like this:
#Model.Temp_Order.ItemName

Using TryUpdateModel to save an object on Edit Post with FormCollection

I'm not sure I understand the best way of doing this.
If I have a model with a large number of fields, then do I have to explicitelly list every one of them in a whitelist under TryUpdateModel, or can I just pass the ForCollection.
The following code doesn't save my edits, is my only alternative to list all my fields one by one?
public ActionResult Edit(int id, FormCollection form)
{
var jobToUpdate = db.Jobs
.Include(x => x.JobNotes)
.Where(x => x.JobID == id)
.SingleOrDefault();
if (TryUpdateModel(jobToUpdate, form))
{
db.Entry(jobToUpdate).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Details", new { id = model.Job.JobID });
}
return RedirectToAction("Details", new { id = model.Job.JobID })
}
Secondly, what is the best way to get a list of just the fields that have changed. If the only field that the user changes is the FirstName field, I'd like to record that in an audit log.
Thanks for your help!
If there are fields on your model that aren't in the form and you don't want users to change then you can use an exclude list. The choice to use an include or exclude list will depend which is largest. An include list is more secure as if you forget to include something it can't be changed. Not using an include, or exclude list will leave you vulnerable to model stuffing where users can post extra values to change details they shouldn't be able to.
public ActionResult Edit(int id, FormCollection form)
{
var jobToUpdate = db.Jobs
.Include(x => x.JobNotes)
.Where(x => x.JobID == id)
.SingleOrDefault();
if (TryUpdateModel(jobToUpdate, String.Empty, null, new [] {"SecretField"}, form))
{
db.SaveChanges();
return RedirectToAction("Details", new { id = model.Job.JobID });
}
// Model not saved - send them back to edit page for corrections
return View(jobToUpdate);
}
If the model is not saved you should not redirect. Show them the same page and make sure your edit view shows model errors.
The most likely reason your code is not saving the model is you're trying to insert a value that is not valid.

code first, multiple bindings

I would like to map my entity class to a database table.
Table rows are: Id, IsActive, BelongsToId
(BelongsToId is a foreign key)
Entity properies are: Id, IsActive, BelongsToId, BelongsTo
(BelongsToId int, BelongsTo is an other entity class' instance)
Is it possible to bind both BelongsToId and BelongsTo properties to BelongsToId data attribute? How?
I try like this, but BelongsToId's value is zero:
partial class KeyConfig : EntityConfiguration<Entities.Key>
{
public KeyConfig ( )
{
Property(s => s.Id).IsIdentity();
Relationship(s => s.BelongsTo).FromProperty(s => s.Keywords);
Property(s => s.IsActive);
Map();
}
void Map ( ) {
MapHierarchy(s => new
{
s.Id,
BelongsToId=s.BelongsTo.Id,
s.IsActive,
}).ToTable("Keywords");
}
}

MVC 4 explicitly load a many to many EF lookup and filter by both keys

I have the following in an MVC4 app. I want to filter the load by both keys, there could be many to many but both the keys together represent a unique row. The goal to to explicitly load these collections only when needed and filter by both sides of the relationship.
I have the following Entity.DBContext, it works but only for the UserId key.
context.UserProfiles.Include(o => o.CoachOfOrginizations).Where(p => p.UserId == UserId).Single()
Also this loads all of them, but of course doesnt filter at all, just showing you so you know that I set up my fluent code properly.
context.Entry(this).Collection(t => t.AdministratorOfOrginizations).Load();
modelBuilder.Entity<UserProfile>()
.HasMany(p => p.CoachOfOrginizations)
.WithMany(t => t.Coaches)
.Map(mc =>
{
mc.ToTable("OrganizationCoaches");
mc.MapLeftKey("UserProfileID");
mc.MapRightKey("OrganizationID");
});
CoachOfOrginizations is the following property on UserProfile.
public ICollection<Organization> CoachOfOrginizations { get; set; }
What i would like is to filter my original .Include above based on Organization.ID (the other key) and the currently used key p.UserId. I've tried the following and it doesn't work, any advice? "this" is the UserProfile object.
context.Entry(this)
.Collection(b => b.CoachOfOrginizations)
.Query()
.Where(p => p.ID == orgID)
.Load();
You can do both filtering in a single query. See conditional includes.
var query = context.UserProfiles
.Where(p => p.UserId == UserId)
.Select(p => new { p, Orgs = p.CoachOfOrginizations.Where(o => o.ID == orgID) });
var profiles = query.AsEnumerable().Select(a => a.p);

Resources