|
Friday, 29 September 2017
Returning a file to View/Download in ASP.NET MVC
Converting string to byte array in C#
public static byte[] ToByteArray(this string str)
{
return System.Text.Encoding.ASCII.GetBytes(str);
}
How to set the filename when downloading a file?
public virtual FileResult DownloadFile(long fileId)
{
string path = ExcelGenerationCode(fileName);
return File(path, "application/vnd.ms-excel","donwload.xls");
}
Fluent NHibernate and Collections Mapping
You can find some bits and pieces about mapping collections with NHibernate in many different places but yet I decided to write another post about it. What is different about my post? I hope to gather here all (in one place) relevant information regarding the most common mappings: many-to-one/one-to-many and many-to-many. In my examples I'm useing Fluent NHibernate API but also XML counterpart are included. All examples are based on the following schema: (subset of AdventureWorks database)
Bidirectional many-to-one/one-to-many
This is the most common type of association, I have used Product and ProductReview tables to depict how it works and how it can be mapped.
In our case each product (one) can have multiple reviews (many). On ProductReview side association can be mapped like this:
which is equal to:
What is FetchType doing? Basically FetchType can be Select or Join, we can define how we want NHibernate to load product for us, consider this code:
For FetchType.Join() NHibernate will call database once with following query:
As you can see review and product are loaded with one call. For FetchType.Select() we will get two calls:
Second call will be executed on demand, it means, only if we try to use Product object like in above example: var productName = review.Product.Name;
In general you have to determine in each case which FetchType is more beneficial for you.
Now, lets check Product side, this is many side of one-to-many association so Product has a collection of reviews, I have chosen to use ISet:
corresponding XML mapping:
Here you can find two confusing things:
Can you see a potential problem here? Each ProductReview knows about its Product, and thanks to cascade="all" everything is configured correctly but still you may end up with just one review in database ... why? I'm using ISet here, so it guarantees that I have only unique objects in the collection. Most of the people know that NHibernate classes should have Equals() and GetHashCode() methods overridden. It is useful when you want to check that two objects represent the same row in a database. People use primary id column in Equals() implementation, primary id is unique so it fits perfectly isn't it? It does if primary key is defined, and in above example, objects are saved in a last line, before that, they don't have any primary id. That is a reason for using different data to determine equality.
Bidirectional many-to-many association
For this association I have used Product, ProductProductPhoto (link) and ProductPhoto tables. Each product can have multiple photos, but each photo can also be associated with multiple products. ProductProductPhoto is just a link table and doesn't have any representation as a separate class. On both sides mapping looks very similarly.
Product side:
which produces XML like this:
and ProductPhoto side:
XML:
In efect Product has a collection of Photos (IList<ProductPhoto> Photos) and ProductPhoto has a collection of products. It's mandatory, in cases like this, to mark one side as inverse="true".
This is fairly straightforward example but unfortunately not very common. In typical case link table has some additional data (like ProductDocument which has ModifiedDate column) and those additional data forces us to use different approach. Among NHibernate best practices you can find general guideline:
and it generates XML like this:
Then we can write code like this:
And that is all what I think is important in this subject ... anything missing? Leave a comment and I will try to add missing parts.
Bidirectional many-to-one/one-to-many
This is the most common type of association, I have used Product and ProductReview tables to depict how it works and how it can be mapped.
In our case each product (one) can have multiple reviews (many). On ProductReview side association can be mapped like this:
References(x => x.Product, "ProductID").FetchType.Join();
<many-to-one fetch="join" name="Product" column="ProductID" />
1: var review = session.Get<ProductReview>("1");
2: var productName = review.Product.Name;
SELECT ... FROM ProductReview pr left outer join Product p on pr.ProductID=p.ProductID WHERE ...
SELECT ... FROM ProductReview pr WHERE ...
SELECT ... FROM Product p WHERE ...
In general you have to determine in each case which FetchType is more beneficial for you.
Now, lets check Product side, this is many side of one-to-many association so Product has a collection of reviews, I have chosen to use ISet:
1: HasMany(x => x.ProductReview)
2: .KeyColumnNames.Add("ProductID")
3: .AsSet()
4: .Inverse()
5: .Cascade.All();
1: <set name="ProductReview" inverse="true" cascade="all">
2: <key column="ProductID" />
3: <one-to-many class="AdventureWorksPlayground.Domain.Production.ProductReview, AdventureWorksPlayground, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
4: </set>
- inverse="true" - it tells NHibernate that other side of this association is a parent. I know that it sounds other way round but that's how it is. ProductReview table has foreign key (and ProductID column) therefore ProductReview controls the association.
What are the implications? In above example review.Product has to be set correctly, as this the property which NHibernate will check to figure our what product is associated with the review. It will ignore collection of reviews on product! - cascade="all" - it tells NHibernate that all events (like save, update, delete) should be propagated down. Calling session.SaveOrUpdate(product) will save (or update) the product itself but also the same event will be applied to all depending objects.
1: var product = new Product
2: {
3: Name = "Bike",
4: SellStartDate = DateTime.Today
5: };
6:
7: product.ProductReview.Add(new ProductReview
8: {
9: Product = product,
10: Rating = 4,
11: ReviewerName = "Bob",
12: ReviewDate = DateTime.Today
13: });
14:
15: product.ProductReview.Add(new ProductReview
16: {
17: Product = product,
18: Rating = 2,
19: ReviewerName = "John",
20: ReviewDate = DateTime.Today
21: });
22:
23:
24: session.SaveOrUpdate(product);
Can you see a potential problem here? Each ProductReview knows about its Product, and thanks to cascade="all" everything is configured correctly but still you may end up with just one review in database ... why? I'm using ISet here, so it guarantees that I have only unique objects in the collection. Most of the people know that NHibernate classes should have Equals() and GetHashCode() methods overridden. It is useful when you want to check that two objects represent the same row in a database. People use primary id column in Equals() implementation, primary id is unique so it fits perfectly isn't it? It does if primary key is defined, and in above example, objects are saved in a last line, before that, they don't have any primary id. That is a reason for using different data to determine equality.
Bidirectional many-to-many association
For this association I have used Product, ProductProductPhoto (link) and ProductPhoto tables. Each product can have multiple photos, but each photo can also be associated with multiple products. ProductProductPhoto is just a link table and doesn't have any representation as a separate class. On both sides mapping looks very similarly.
Product side:
1: HasManyToMany(x => x.Photos)
2: .AsBag()
3: .WithTableName("Production.ProductProductPhoto")
4: .WithParentKeyColumn("ProductID")
5: .WithChildKeyColumn("ProductPhotoID")
6: .Cascade.All();
1: <bag name="Photos" cascade="all" table="Production.ProductProductPhoto">
2: <key column="ProductID" />
3: <many-to-many column="ProductPhotoID" class="AdventureWorksPlayground.Domain.Production.ProductPhoto, AdventureWorksPlayground, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
4: </bag>
1: HasManyToMany(x => x.Products)
2: .AsBag()
3: .WithTableName("Production.ProductProductPhoto")
4: .WithParentKeyColumn("ProductPhotoID")
5: .WithChildKeyColumn("ProductID")
6: .Inverse();
1: <bag name="Products" inverse="true" table="Production.ProductProductPhoto">
2: <key column="ProductPhotoID" />
3: <many-to-many column="ProductID" class="AdventureWorksPlayground.Domain.Production.Product, AdventureWorksPlayground, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
4: </bag>
This is fairly straightforward example but unfortunately not very common. In typical case link table has some additional data (like ProductDocument which has ModifiedDate column) and those additional data forces us to use different approach. Among NHibernate best practices you can find general guideline:
Good usecases for a real many-to-many associations are rare. Most of the time you need additional information stored in the "link table". In this case, it is much better to use two one-to-many associations to an intermediate link class. In fact, we think that most associations are one-to-many and many-to-one, you should be careful when using any other association style and ask yourself if it is really necessary.So, in fact, for tables Product, Document and ProductDocument, we have to create three classes and three mappings. Both Product and Document have a link to each other through ProductDocument object. Interesting part is ProductDocument which has composite primary id (two columns) which can be mapped in a following way:
1: public class ProductDocumentMap : ClassMap<ProductDocument>
2: {
3: public ProductDocumentMap()
4: {
5: UseCompositeId()
6: .WithKeyReference(x => x.Product, "ProductID")
7: .WithKeyReference(x => x.Document, "DocumentID");
8:
9: Map(x => x.ModifiedDate).Not.Nullable();
10: }
11: }
1: <class name="ProductDocument" table="Production.ProductDocument" xmlns="urn:nhibernate-mapping-2.2">
2: <composite-id>
3: <key-many-to-one class="AdventureWorksPlayground.Domain.Production.Product, AdventureWorksPlayground, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" name="Product" column="ProductID" />
4: <key-many-to-one class="AdventureWorksPlayground.Domain.Production.Document, AdventureWorksPlayground, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" name="Document" column="DocumentID" />
5: </composite-id>
6: <property name="ModifiedDate" column="ModifiedDate" not-null="true" type="DateTime">
7: <column name="ModifiedDate" />
8: </property>
9: </class>
1: var product = CreateNewProduct();
2: var photo1 = CreateNewPhoto();
3: var photo2 = CreateNewPhoto();
4:
5: product.Photos.Add(photo1);
6: product.Photos.Add(photo2);
7:
8: // we don't have to save photos because of Cascade.SaveUpdate()
9: // INSERT INTO [Production.Product]
10: // INSERT INTO [Production.ProductPhoto]
11: // INSERT INTO [Production.ProductPhoto]
12: // INSERT INTO [Production.ProductProductPhoto]
13: // INSERT INTO [Production.ProductProductPhoto]
14: session.SaveOrUpdate(product);
NHibernate serializing lazy-loaded entities
You can't lazy-load a collection after you've closed the
NHibernate.ISession
object from which it was loaded. The only options you have are:- Keep the
ISession
open until you've serialized the data. - Turn off lazy loading.
- make sure you fetch all the lazy loaded collections before closing the session.
- use Not.LazyLoad()
Bootstrap Dropdowns
<div class="dropdown">
<button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">Dropdown Example
<span class="caret"></span></button>
<ul class="dropdown-menu">
<li><a href="#">HTML</a></li>
<li><a href="#">CSS</a></li>
<li class="divider"></li>
<li class="dropdown-header">Dropdown header 1</li>
<li><a href="#">JavaScript</a></li>
<li class="disabled"><a href="#">CSS</a></li>
<li class="active"><a href="#">HTML</a></li>
<ul class="dropdown-menu dropdown-menu-right">
</ul>
</div>
<button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">Dropdown Example
<span class="caret"></span></button>
<ul class="dropdown-menu">
<li><a href="#">HTML</a></li>
<li><a href="#">CSS</a></li>
<li class="divider"></li>
<li class="dropdown-header">Dropdown header 1</li>
<li><a href="#">JavaScript</a></li>
<li class="disabled"><a href="#">CSS</a></li>
<li class="active"><a href="#">HTML</a></li>
<ul class="dropdown-menu dropdown-menu-right">
</ul>
</div>
Subscribe to:
Posts (Atom)
Blog Archive
-
▼
2017
(142)
-
▼
September
(53)
- Returning a file to View/Download in ASP.NET MVC
- Converting string to byte array in C#
- How to set the filename when downloading a file?
- Fluent NHibernate and Collections Mapping
- NHibernate serializing lazy-loaded entities
- Bootstrap Dropdowns
- nhibernate class mappings
- Authorize Attribute with Multiple Roles
- Displaying Labels using Bootstrap
- How to search sql server database for string?
- Edit Metadata of PDF File with C#
- Right pad a string with variable number of spaces
- How can I check if an SQL result contains a newlin...
- How do you specify a different port number in SQL ...
- Hello World PDF.JS Walkthrough
- CAST and CONVERT (Transact-SQL)
- Windows search - full text search in c#
- How to configure fluent nHibernate with MySQL
- Cannot resolve the collation conflict between “SQL...
- SYSDATETIME (Transact-SQL)
- Mapping to collection in PetaPoco?
- Extract key/values from FormCollection in ASP.NET ...
- NHibernate Insert Into Table
- Need help with delete record in asp.net using Nhib...
- Why isn't NHibernate deleting from the database?
- PetaPoco
- How to create a SQL Server stored procedure with p...
- Reading PDF documents in .Net
- Read/Modify PDF Metadata using iTextSharp
- Google Cloud Print using C#
- NHibernate - Fluent Hibernate
- How get data from table with NHibernate by where?
- Cannot convert expression type 'NHibernate.IQueryO...
- MVC If statement in View
- How do I get request parameters in ASP.NET MVC
- Convert file path to a file URI?
- ASP.NET Actionlink with glyphicon and text with di...
- Center a column using Twitter Bootstrap 3
- NHibernate QueryOver distinct
- How use Distinct in linq & linq to NHibernate by s...
- MVC 4 how pass data correctly from controller to view
- Multiple Models in Single View in MVC
- How to retrieve form values from HTTPPOST, diction...
- How to get DropDownList SelectedValue in Controlle...
- Adding SelectListItem manually to SelectList to us...
- How to cache data in a MVC application
- Searching with a dropdown list in asp.net MVC
- Cannot convert type 'System.Collections.Generic.Li...
- Cannot get distinct values using a SelectListitem
- How to return PDF to browser in MVC?
- Show menu item only for logged-on users
- Generate GUID in MySQL for existing Data?
- How do I redirect to the previous action in ASP.NE...
-
▼
September
(53)